<!DOCTYPE html>
<html lang="en-US">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <title>redo日志（上） | AJ</title>
    <meta name="generator" content="VuePress 1.5.0">
    <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon">
    <script>
            var _hmt = _hmt || [];
            (function() {
            var hm = document.createElement("script");
            hm.src = "https://hm.baidu.com/hm.js?51b8c2e72d1adf96524638ce85bb7d72";
            var s = document.getElementsByTagName("script")[0]; 
            s.parentNode.insertBefore(hm, s);

            // 引入谷歌,不需要可删除这段
            var hm1 = document.createElement("script");
            hm1.src = "https://www.googletagmanager.com/gtag/js?id=G-B7351EYS04";
            var s1 = document.getElementsByTagName("script")[0]; 
            s1.parentNode.insertBefore(hm1, s1);
            })();

            // 谷歌加载,不需要可删除
            window.dataLayer = window.dataLayer || [];
            function gtag(){dataLayer.push(arguments);}
            gtag('js', new Date());

            gtag('config', 'G-B7351EYS04');
        </script>
    <meta name="description" content="阿俊博客|记录一个程序员的成长历程 阿俊博客(blog.zhequtao.com)记录一个后端程序员的成长历程,分享他的学习笔记和心得,还有些开发必备技巧哦! java golang web html dev开发">
    <link rel="preload" href="/assets/css/0.styles.a3df589e.css" as="style"><link rel="preload" href="/assets/js/app.cb35c8f6.js" as="script"><link rel="preload" href="/assets/js/2.063846a6.js" as="script"><link rel="preload" href="/assets/js/4.1ffb4609.js" as="script"><link rel="preload" href="/assets/js/611.bb8058c9.js" as="script"><link rel="prefetch" href="/assets/js/10.5629fe4d.js"><link rel="prefetch" href="/assets/js/100.8417ccea.js"><link rel="prefetch" href="/assets/js/101.37fdb377.js"><link rel="prefetch" href="/assets/js/102.848b686d.js"><link rel="prefetch" href="/assets/js/103.6a2489a0.js"><link rel="prefetch" href="/assets/js/104.99e8899f.js"><link rel="prefetch" href="/assets/js/105.8b741763.js"><link rel="prefetch" href="/assets/js/106.08163715.js"><link rel="prefetch" href="/assets/js/107.21801349.js"><link rel="prefetch" href="/assets/js/108.e3a2892b.js"><link rel="prefetch" href="/assets/js/109.dab5618c.js"><link rel="prefetch" href="/assets/js/11.cddc1623.js"><link rel="prefetch" href="/assets/js/110.f5249b39.js"><link rel="prefetch" href="/assets/js/111.9abf8bce.js"><link rel="prefetch" href="/assets/js/112.8eb86924.js"><link rel="prefetch" href="/assets/js/113.c180ed46.js"><link rel="prefetch" href="/assets/js/114.2370f5b5.js"><link rel="prefetch" href="/assets/js/115.88dc3fd8.js"><link rel="prefetch" href="/assets/js/116.63403600.js"><link rel="prefetch" href="/assets/js/117.83674aa0.js"><link rel="prefetch" href="/assets/js/118.9c58c685.js"><link rel="prefetch" href="/assets/js/119.621f9a70.js"><link rel="prefetch" href="/assets/js/12.ff3d03f5.js"><link rel="prefetch" href="/assets/js/120.a6d2b7f7.js"><link rel="prefetch" href="/assets/js/121.ae0ce9d1.js"><link rel="prefetch" href="/assets/js/122.de240e6d.js"><link rel="prefetch" href="/assets/js/123.b043e3e4.js"><link rel="prefetch" href="/assets/js/124.550af937.js"><link rel="prefetch" href="/assets/js/125.6f06b34c.js"><link rel="prefetch" href="/assets/js/126.38d64604.js"><link rel="prefetch" href="/assets/js/127.a948db56.js"><link rel="prefetch" href="/assets/js/128.4ca789e0.js"><link rel="prefetch" href="/assets/js/129.59be4505.js"><link rel="prefetch" href="/assets/js/13.e9f75cc3.js"><link rel="prefetch" href="/assets/js/130.ddae76a9.js"><link rel="prefetch" href="/assets/js/131.d969c265.js"><link rel="prefetch" href="/assets/js/132.5f43ce5c.js"><link rel="prefetch" href="/assets/js/133.b651af22.js"><link rel="prefetch" href="/assets/js/134.2499236a.js"><link rel="prefetch" href="/assets/js/135.4180596c.js"><link rel="prefetch" href="/assets/js/136.2c309233.js"><link rel="prefetch" href="/assets/js/137.72ca42dd.js"><link rel="prefetch" href="/assets/js/138.3772cd38.js"><link rel="prefetch" href="/assets/js/139.1d0a53da.js"><link rel="prefetch" href="/assets/js/14.be4b89ed.js"><link rel="prefetch" href="/assets/js/140.22368353.js"><link rel="prefetch" href="/assets/js/141.a14aef3c.js"><link rel="prefetch" href="/assets/js/142.2041ce3a.js"><link rel="prefetch" href="/assets/js/143.377262ec.js"><link rel="prefetch" href="/assets/js/144.8fcbc368.js"><link rel="prefetch" href="/assets/js/145.46da36bf.js"><link rel="prefetch" href="/assets/js/146.eceae0d9.js"><link rel="prefetch" href="/assets/js/147.e1bd6531.js"><link rel="prefetch" href="/assets/js/148.76f193ce.js"><link rel="prefetch" href="/assets/js/149.587bd581.js"><link rel="prefetch" href="/assets/js/15.e3219ac0.js"><link rel="prefetch" href="/assets/js/150.169c71e0.js"><link rel="prefetch" href="/assets/js/151.384021ea.js"><link rel="prefetch" href="/assets/js/152.0f20cf03.js"><link rel="prefetch" href="/assets/js/153.fd94af1e.js"><link rel="prefetch" href="/assets/js/154.a550f5dc.js"><link rel="prefetch" href="/assets/js/155.ba1ae86e.js"><link rel="prefetch" href="/assets/js/156.3b98ded0.js"><link rel="prefetch" href="/assets/js/157.cd378596.js"><link rel="prefetch" href="/assets/js/158.c138d0df.js"><link rel="prefetch" href="/assets/js/159.2635f7f4.js"><link rel="prefetch" href="/assets/js/16.c9c35d42.js"><link rel="prefetch" href="/assets/js/160.d51b4126.js"><link rel="prefetch" href="/assets/js/161.5dc29e7b.js"><link rel="prefetch" href="/assets/js/162.f257a92b.js"><link rel="prefetch" href="/assets/js/163.9eb75e40.js"><link rel="prefetch" href="/assets/js/164.8fb1e22b.js"><link rel="prefetch" href="/assets/js/165.49255503.js"><link rel="prefetch" href="/assets/js/166.e54539e6.js"><link rel="prefetch" href="/assets/js/167.a06acdb0.js"><link rel="prefetch" href="/assets/js/168.948ab620.js"><link rel="prefetch" href="/assets/js/169.7d756812.js"><link rel="prefetch" href="/assets/js/17.81067bc8.js"><link rel="prefetch" href="/assets/js/170.ffe63330.js"><link rel="prefetch" href="/assets/js/171.835398b9.js"><link rel="prefetch" href="/assets/js/172.3987be39.js"><link rel="prefetch" href="/assets/js/173.e3cedb8a.js"><link rel="prefetch" href="/assets/js/174.11a32588.js"><link rel="prefetch" href="/assets/js/175.da6f9782.js"><link rel="prefetch" href="/assets/js/176.50e55edc.js"><link rel="prefetch" href="/assets/js/177.a89a1d17.js"><link rel="prefetch" href="/assets/js/178.7ad3ce84.js"><link rel="prefetch" href="/assets/js/179.98a1343b.js"><link rel="prefetch" href="/assets/js/18.b67caf4c.js"><link rel="prefetch" href="/assets/js/180.4e98599b.js"><link rel="prefetch" href="/assets/js/181.dd885afd.js"><link rel="prefetch" href="/assets/js/182.789990c8.js"><link rel="prefetch" href="/assets/js/183.f11ca2fd.js"><link rel="prefetch" href="/assets/js/184.fcf128ec.js"><link rel="prefetch" href="/assets/js/185.54e1e9b6.js"><link rel="prefetch" href="/assets/js/186.db91021a.js"><link rel="prefetch" href="/assets/js/187.5309dd42.js"><link rel="prefetch" href="/assets/js/188.615821ea.js"><link rel="prefetch" href="/assets/js/189.f23f1d42.js"><link rel="prefetch" href="/assets/js/19.294a011c.js"><link rel="prefetch" href="/assets/js/190.efe894bc.js"><link rel="prefetch" href="/assets/js/191.0d14904a.js"><link rel="prefetch" href="/assets/js/192.efd25a9e.js"><link rel="prefetch" href="/assets/js/193.88151f34.js"><link rel="prefetch" href="/assets/js/194.efedce14.js"><link rel="prefetch" href="/assets/js/195.03ac15bb.js"><link rel="prefetch" href="/assets/js/196.fbc18389.js"><link rel="prefetch" href="/assets/js/197.0257ab5e.js"><link rel="prefetch" href="/assets/js/198.f1de2817.js"><link rel="prefetch" href="/assets/js/199.8f1c166b.js"><link rel="prefetch" href="/assets/js/20.1a41edb1.js"><link rel="prefetch" href="/assets/js/200.4af99727.js"><link rel="prefetch" href="/assets/js/201.9f8caef1.js"><link rel="prefetch" href="/assets/js/202.6f07d705.js"><link rel="prefetch" href="/assets/js/203.5012fe50.js"><link rel="prefetch" href="/assets/js/204.3a0dfd8e.js"><link rel="prefetch" href="/assets/js/205.0ba9b606.js"><link rel="prefetch" href="/assets/js/206.663a49ec.js"><link rel="prefetch" href="/assets/js/207.b2406149.js"><link rel="prefetch" href="/assets/js/208.b0b2dfd8.js"><link rel="prefetch" href="/assets/js/209.41a0ec9f.js"><link rel="prefetch" href="/assets/js/21.b6ea6f9a.js"><link rel="prefetch" href="/assets/js/210.6f36beb8.js"><link rel="prefetch" href="/assets/js/211.90ef6e5c.js"><link rel="prefetch" href="/assets/js/212.42339063.js"><link rel="prefetch" href="/assets/js/213.a2bfeda9.js"><link rel="prefetch" href="/assets/js/214.5c7eb42a.js"><link rel="prefetch" href="/assets/js/215.18260ae5.js"><link rel="prefetch" href="/assets/js/216.7678fd29.js"><link rel="prefetch" href="/assets/js/217.9d936f88.js"><link rel="prefetch" href="/assets/js/218.bac403c4.js"><link rel="prefetch" href="/assets/js/219.9d8cb16b.js"><link rel="prefetch" href="/assets/js/22.367cc253.js"><link rel="prefetch" href="/assets/js/220.375b7707.js"><link rel="prefetch" href="/assets/js/221.3e400da4.js"><link rel="prefetch" href="/assets/js/222.8fbd2857.js"><link rel="prefetch" href="/assets/js/223.76a10075.js"><link rel="prefetch" href="/assets/js/224.ff94cc4e.js"><link rel="prefetch" href="/assets/js/225.d4688ca6.js"><link rel="prefetch" href="/assets/js/226.b13b18af.js"><link rel="prefetch" href="/assets/js/227.288d0f96.js"><link rel="prefetch" href="/assets/js/228.60430ac0.js"><link rel="prefetch" href="/assets/js/229.da728342.js"><link rel="prefetch" href="/assets/js/23.bc3de730.js"><link rel="prefetch" href="/assets/js/230.d8417d20.js"><link rel="prefetch" href="/assets/js/231.6a9ce0b4.js"><link rel="prefetch" href="/assets/js/232.7611b413.js"><link rel="prefetch" href="/assets/js/233.94712cf9.js"><link rel="prefetch" href="/assets/js/234.93888298.js"><link rel="prefetch" href="/assets/js/235.62506981.js"><link rel="prefetch" href="/assets/js/236.5a055c7c.js"><link rel="prefetch" href="/assets/js/237.0a6c4902.js"><link rel="prefetch" href="/assets/js/238.e5f37663.js"><link rel="prefetch" href="/assets/js/239.331bba86.js"><link rel="prefetch" href="/assets/js/24.82f0901c.js"><link rel="prefetch" href="/assets/js/240.59591cfc.js"><link rel="prefetch" href="/assets/js/241.ce671f47.js"><link rel="prefetch" href="/assets/js/242.fb2542fa.js"><link rel="prefetch" href="/assets/js/243.74abc73d.js"><link rel="prefetch" href="/assets/js/244.ecd707b2.js"><link rel="prefetch" href="/assets/js/245.d728367b.js"><link rel="prefetch" href="/assets/js/246.9270e7fe.js"><link rel="prefetch" href="/assets/js/247.a421ba15.js"><link rel="prefetch" href="/assets/js/248.e759132e.js"><link rel="prefetch" href="/assets/js/249.3077fb46.js"><link rel="prefetch" href="/assets/js/25.95c551dc.js"><link rel="prefetch" href="/assets/js/250.5fe4dd03.js"><link rel="prefetch" href="/assets/js/251.4b8fe76c.js"><link rel="prefetch" href="/assets/js/252.0d1cf7ea.js"><link rel="prefetch" href="/assets/js/253.89d16ba0.js"><link rel="prefetch" href="/assets/js/254.8d1afc68.js"><link rel="prefetch" href="/assets/js/255.64e680cb.js"><link rel="prefetch" href="/assets/js/256.9defbd0e.js"><link rel="prefetch" href="/assets/js/257.1fef24fd.js"><link rel="prefetch" href="/assets/js/258.4e205286.js"><link rel="prefetch" href="/assets/js/259.f3d56efc.js"><link rel="prefetch" href="/assets/js/26.7fe56bac.js"><link rel="prefetch" href="/assets/js/260.378299e6.js"><link rel="prefetch" href="/assets/js/261.8e4fb397.js"><link rel="prefetch" href="/assets/js/262.54595d98.js"><link rel="prefetch" href="/assets/js/263.fb333dc1.js"><link rel="prefetch" href="/assets/js/264.13d13301.js"><link rel="prefetch" href="/assets/js/265.c85104bc.js"><link rel="prefetch" href="/assets/js/266.9f3d1f1c.js"><link rel="prefetch" href="/assets/js/267.fb392815.js"><link rel="prefetch" href="/assets/js/268.add7eacb.js"><link rel="prefetch" href="/assets/js/269.7e49fcc7.js"><link rel="prefetch" href="/assets/js/27.5547e5f0.js"><link rel="prefetch" href="/assets/js/270.22342070.js"><link rel="prefetch" href="/assets/js/271.59917b1a.js"><link rel="prefetch" href="/assets/js/272.4a4751d5.js"><link rel="prefetch" href="/assets/js/273.f4c2fa5c.js"><link rel="prefetch" href="/assets/js/274.1208bc94.js"><link rel="prefetch" href="/assets/js/275.f6528753.js"><link rel="prefetch" href="/assets/js/276.a68772cd.js"><link rel="prefetch" href="/assets/js/277.f154ab32.js"><link rel="prefetch" href="/assets/js/278.bb616a63.js"><link rel="prefetch" href="/assets/js/279.6a356cff.js"><link rel="prefetch" href="/assets/js/28.b08b2847.js"><link rel="prefetch" href="/assets/js/280.5afc20fc.js"><link rel="prefetch" href="/assets/js/281.3cd86225.js"><link rel="prefetch" href="/assets/js/282.3ecb92aa.js"><link rel="prefetch" href="/assets/js/283.85159ea7.js"><link rel="prefetch" href="/assets/js/284.b6545c68.js"><link rel="prefetch" href="/assets/js/285.5e83ee29.js"><link rel="prefetch" href="/assets/js/286.2aad298d.js"><link rel="prefetch" href="/assets/js/287.3ca76244.js"><link rel="prefetch" href="/assets/js/288.5b17963d.js"><link rel="prefetch" href="/assets/js/289.f47a759b.js"><link rel="prefetch" href="/assets/js/29.562dbf7d.js"><link rel="prefetch" href="/assets/js/290.36b603c7.js"><link rel="prefetch" href="/assets/js/291.a9bd8951.js"><link rel="prefetch" href="/assets/js/292.dfc54f28.js"><link rel="prefetch" href="/assets/js/293.2d061212.js"><link rel="prefetch" href="/assets/js/294.6d564a9e.js"><link rel="prefetch" href="/assets/js/295.a31dd593.js"><link rel="prefetch" href="/assets/js/296.3101e5e8.js"><link rel="prefetch" href="/assets/js/297.7efde936.js"><link rel="prefetch" href="/assets/js/298.8bb3aa68.js"><link rel="prefetch" href="/assets/js/299.8b51e6bd.js"><link rel="prefetch" href="/assets/js/3.76257eb7.js"><link rel="prefetch" href="/assets/js/30.221adea2.js"><link rel="prefetch" href="/assets/js/300.62effe45.js"><link rel="prefetch" href="/assets/js/301.98c863c5.js"><link rel="prefetch" href="/assets/js/302.e3493ab2.js"><link rel="prefetch" href="/assets/js/303.800c8028.js"><link rel="prefetch" href="/assets/js/304.b6f08986.js"><link rel="prefetch" href="/assets/js/305.09af356b.js"><link rel="prefetch" href="/assets/js/306.d0d3589d.js"><link rel="prefetch" href="/assets/js/307.ee2fd249.js"><link rel="prefetch" href="/assets/js/308.f3f76368.js"><link rel="prefetch" href="/assets/js/309.d2b5ce40.js"><link rel="prefetch" href="/assets/js/31.334fc8bb.js"><link rel="prefetch" href="/assets/js/310.b4fa2feb.js"><link rel="prefetch" href="/assets/js/311.7d747ef3.js"><link rel="prefetch" href="/assets/js/312.89bdff40.js"><link rel="prefetch" href="/assets/js/313.875b82fe.js"><link rel="prefetch" href="/assets/js/314.0bbe51c4.js"><link rel="prefetch" href="/assets/js/315.cc07dbcf.js"><link rel="prefetch" href="/assets/js/316.bc72b152.js"><link rel="prefetch" href="/assets/js/317.55462812.js"><link rel="prefetch" href="/assets/js/318.a158fda0.js"><link rel="prefetch" href="/assets/js/319.b03a5bd2.js"><link rel="prefetch" href="/assets/js/32.d6826b16.js"><link rel="prefetch" href="/assets/js/320.a5bd19b0.js"><link rel="prefetch" href="/assets/js/321.4f9faaa7.js"><link rel="prefetch" href="/assets/js/322.dbd3b4fa.js"><link rel="prefetch" href="/assets/js/323.a04e2062.js"><link rel="prefetch" href="/assets/js/324.c45b46cf.js"><link rel="prefetch" href="/assets/js/325.cd1460c4.js"><link rel="prefetch" href="/assets/js/326.bd90ef85.js"><link rel="prefetch" href="/assets/js/327.8bf38ef7.js"><link rel="prefetch" href="/assets/js/328.99e9aed3.js"><link rel="prefetch" href="/assets/js/329.de0012cb.js"><link rel="prefetch" href="/assets/js/33.b1059062.js"><link rel="prefetch" href="/assets/js/330.59f11391.js"><link rel="prefetch" href="/assets/js/331.6d16a13c.js"><link rel="prefetch" href="/assets/js/332.922ca235.js"><link rel="prefetch" href="/assets/js/333.c94c3602.js"><link rel="prefetch" href="/assets/js/334.77e02010.js"><link rel="prefetch" href="/assets/js/335.1e0c4f7b.js"><link rel="prefetch" href="/assets/js/336.5675dc4f.js"><link rel="prefetch" href="/assets/js/337.bb6e11dc.js"><link rel="prefetch" href="/assets/js/338.294981e9.js"><link rel="prefetch" href="/assets/js/339.d0376372.js"><link rel="prefetch" href="/assets/js/34.0c7d5782.js"><link rel="prefetch" href="/assets/js/340.64596428.js"><link rel="prefetch" href="/assets/js/341.ec0f9409.js"><link rel="prefetch" href="/assets/js/342.7abc47c4.js"><link rel="prefetch" href="/assets/js/343.4262d486.js"><link rel="prefetch" href="/assets/js/344.8729ad8c.js"><link rel="prefetch" href="/assets/js/345.c210d888.js"><link rel="prefetch" href="/assets/js/346.6f42f7cb.js"><link rel="prefetch" href="/assets/js/347.81b41ae5.js"><link rel="prefetch" href="/assets/js/348.07eca37c.js"><link rel="prefetch" href="/assets/js/349.8019d6f3.js"><link rel="prefetch" href="/assets/js/35.ae14e37f.js"><link rel="prefetch" href="/assets/js/350.57da2e7b.js"><link rel="prefetch" href="/assets/js/351.2e99afdf.js"><link rel="prefetch" href="/assets/js/352.67dd88b7.js"><link rel="prefetch" href="/assets/js/353.15b9f624.js"><link rel="prefetch" href="/assets/js/354.a63e8432.js"><link rel="prefetch" href="/assets/js/355.bbc16ee9.js"><link rel="prefetch" href="/assets/js/356.ff63d3bb.js"><link rel="prefetch" href="/assets/js/357.4fb2d941.js"><link rel="prefetch" href="/assets/js/358.55182977.js"><link rel="prefetch" href="/assets/js/359.265c3d26.js"><link rel="prefetch" href="/assets/js/36.b9ed4cf1.js"><link rel="prefetch" href="/assets/js/360.ced80eb3.js"><link rel="prefetch" href="/assets/js/361.afe6ba84.js"><link rel="prefetch" href="/assets/js/362.c2b62518.js"><link rel="prefetch" href="/assets/js/363.0c4a4800.js"><link rel="prefetch" href="/assets/js/364.ce60291b.js"><link rel="prefetch" href="/assets/js/365.0e3a61f9.js"><link rel="prefetch" href="/assets/js/366.d53ccb03.js"><link rel="prefetch" href="/assets/js/367.689e464d.js"><link rel="prefetch" href="/assets/js/368.418c571f.js"><link rel="prefetch" href="/assets/js/369.c2fff3c8.js"><link rel="prefetch" href="/assets/js/37.a021ac57.js"><link rel="prefetch" href="/assets/js/370.a932b958.js"><link rel="prefetch" href="/assets/js/371.7d153241.js"><link rel="prefetch" href="/assets/js/372.fb9878fa.js"><link rel="prefetch" href="/assets/js/373.85772e03.js"><link rel="prefetch" href="/assets/js/374.b4a8b1b6.js"><link rel="prefetch" href="/assets/js/375.32f70596.js"><link rel="prefetch" href="/assets/js/376.a16d79a8.js"><link rel="prefetch" href="/assets/js/377.c996b7e1.js"><link rel="prefetch" href="/assets/js/378.d37d15c7.js"><link rel="prefetch" href="/assets/js/379.b81ba7dd.js"><link rel="prefetch" href="/assets/js/38.89138658.js"><link rel="prefetch" href="/assets/js/380.524c9b31.js"><link rel="prefetch" href="/assets/js/381.7ebfd6db.js"><link rel="prefetch" href="/assets/js/382.29edda0f.js"><link rel="prefetch" href="/assets/js/383.9642a212.js"><link rel="prefetch" href="/assets/js/384.086e3b42.js"><link rel="prefetch" href="/assets/js/385.a9bb46a8.js"><link rel="prefetch" href="/assets/js/386.f2561a39.js"><link rel="prefetch" href="/assets/js/387.ba9b6aaa.js"><link rel="prefetch" href="/assets/js/388.e0ace495.js"><link rel="prefetch" href="/assets/js/389.ba8c09dd.js"><link rel="prefetch" href="/assets/js/39.04f331e3.js"><link rel="prefetch" href="/assets/js/390.de1bb48b.js"><link rel="prefetch" href="/assets/js/391.7cc6edeb.js"><link rel="prefetch" href="/assets/js/392.0493a6f7.js"><link rel="prefetch" href="/assets/js/393.ba2d3e62.js"><link rel="prefetch" href="/assets/js/394.b3aa9224.js"><link rel="prefetch" href="/assets/js/395.f4df3a60.js"><link rel="prefetch" href="/assets/js/396.09644790.js"><link rel="prefetch" href="/assets/js/397.76163964.js"><link rel="prefetch" href="/assets/js/398.377fd8fc.js"><link rel="prefetch" href="/assets/js/399.39059be5.js"><link rel="prefetch" href="/assets/js/40.a21abf05.js"><link rel="prefetch" href="/assets/js/400.559a547f.js"><link rel="prefetch" href="/assets/js/401.bc6d738c.js"><link rel="prefetch" href="/assets/js/402.c504ed7b.js"><link rel="prefetch" href="/assets/js/403.77a0af9c.js"><link rel="prefetch" href="/assets/js/404.0f408cc6.js"><link rel="prefetch" href="/assets/js/405.90b0bab6.js"><link rel="prefetch" href="/assets/js/406.01b11432.js"><link rel="prefetch" href="/assets/js/407.58991ce5.js"><link rel="prefetch" href="/assets/js/408.9806278e.js"><link rel="prefetch" href="/assets/js/409.8d9b4bb3.js"><link rel="prefetch" href="/assets/js/41.6bcfc592.js"><link rel="prefetch" href="/assets/js/410.02dee620.js"><link rel="prefetch" href="/assets/js/411.3d12d3a6.js"><link rel="prefetch" href="/assets/js/412.37a62624.js"><link rel="prefetch" href="/assets/js/413.bda7ca34.js"><link rel="prefetch" href="/assets/js/414.2abb6547.js"><link rel="prefetch" href="/assets/js/415.1d271923.js"><link rel="prefetch" href="/assets/js/416.d1b11dfe.js"><link rel="prefetch" href="/assets/js/417.fcbf07ff.js"><link rel="prefetch" href="/assets/js/418.524d40ba.js"><link rel="prefetch" href="/assets/js/419.f264e463.js"><link rel="prefetch" href="/assets/js/42.ec85a270.js"><link rel="prefetch" href="/assets/js/420.8b99e60d.js"><link rel="prefetch" href="/assets/js/421.c697d876.js"><link rel="prefetch" href="/assets/js/422.4af54ae0.js"><link rel="prefetch" href="/assets/js/423.b75f24ff.js"><link rel="prefetch" href="/assets/js/424.ea80054f.js"><link rel="prefetch" href="/assets/js/425.804b48b0.js"><link rel="prefetch" href="/assets/js/426.ffed8383.js"><link rel="prefetch" href="/assets/js/427.2040bd22.js"><link rel="prefetch" href="/assets/js/428.b878fb56.js"><link rel="prefetch" href="/assets/js/429.f81fd922.js"><link rel="prefetch" href="/assets/js/43.c174449d.js"><link rel="prefetch" href="/assets/js/430.16f328ab.js"><link rel="prefetch" href="/assets/js/431.56f11924.js"><link rel="prefetch" href="/assets/js/432.e4c77710.js"><link rel="prefetch" href="/assets/js/433.29acf14b.js"><link rel="prefetch" href="/assets/js/434.33ee22fc.js"><link rel="prefetch" href="/assets/js/435.516f7600.js"><link rel="prefetch" href="/assets/js/436.28ae526a.js"><link rel="prefetch" href="/assets/js/437.b9bac473.js"><link rel="prefetch" href="/assets/js/438.711bd934.js"><link rel="prefetch" href="/assets/js/439.fe5f28bd.js"><link rel="prefetch" href="/assets/js/44.8704338b.js"><link rel="prefetch" href="/assets/js/440.b2f48747.js"><link rel="prefetch" href="/assets/js/441.4862a724.js"><link rel="prefetch" href="/assets/js/442.751f8ae7.js"><link rel="prefetch" href="/assets/js/443.9998dbe9.js"><link rel="prefetch" href="/assets/js/444.23d3f688.js"><link rel="prefetch" href="/assets/js/445.72419f35.js"><link rel="prefetch" href="/assets/js/446.21e02b7b.js"><link rel="prefetch" href="/assets/js/447.6bd039e5.js"><link rel="prefetch" href="/assets/js/448.af29ff31.js"><link rel="prefetch" href="/assets/js/449.bbdca196.js"><link rel="prefetch" href="/assets/js/45.f8a2a3b3.js"><link rel="prefetch" href="/assets/js/450.32e470b8.js"><link rel="prefetch" href="/assets/js/451.f4c8ff6a.js"><link rel="prefetch" href="/assets/js/452.c0ec8943.js"><link rel="prefetch" href="/assets/js/453.5af475c6.js"><link rel="prefetch" href="/assets/js/454.567aa6c1.js"><link rel="prefetch" href="/assets/js/455.326072d1.js"><link rel="prefetch" href="/assets/js/456.64b88847.js"><link rel="prefetch" href="/assets/js/457.61c91559.js"><link rel="prefetch" href="/assets/js/458.4f4d43d6.js"><link rel="prefetch" href="/assets/js/459.a88891cb.js"><link rel="prefetch" href="/assets/js/46.90855a0f.js"><link rel="prefetch" href="/assets/js/460.fb9e15f6.js"><link rel="prefetch" href="/assets/js/461.998a4991.js"><link rel="prefetch" href="/assets/js/462.56ecfb03.js"><link rel="prefetch" href="/assets/js/463.582cd053.js"><link rel="prefetch" href="/assets/js/464.f12a0050.js"><link rel="prefetch" href="/assets/js/465.cc3b08a8.js"><link rel="prefetch" href="/assets/js/466.ea7e4ce2.js"><link rel="prefetch" href="/assets/js/467.58700d93.js"><link rel="prefetch" href="/assets/js/468.bb9998cd.js"><link rel="prefetch" href="/assets/js/469.232d261d.js"><link rel="prefetch" href="/assets/js/47.02516d33.js"><link rel="prefetch" href="/assets/js/470.90ab2be8.js"><link rel="prefetch" href="/assets/js/471.3652fec6.js"><link rel="prefetch" href="/assets/js/472.bc7517c9.js"><link rel="prefetch" href="/assets/js/473.27b7892f.js"><link rel="prefetch" href="/assets/js/474.0d488768.js"><link rel="prefetch" href="/assets/js/475.bc33cf17.js"><link rel="prefetch" href="/assets/js/476.76ce67eb.js"><link rel="prefetch" href="/assets/js/477.a20657f6.js"><link rel="prefetch" href="/assets/js/478.8905ef26.js"><link rel="prefetch" href="/assets/js/479.23ec3dc9.js"><link rel="prefetch" href="/assets/js/48.8d38983c.js"><link rel="prefetch" href="/assets/js/480.105bf58e.js"><link rel="prefetch" href="/assets/js/481.d62a3699.js"><link rel="prefetch" href="/assets/js/482.6cb10cdb.js"><link rel="prefetch" href="/assets/js/483.15b9ef53.js"><link rel="prefetch" href="/assets/js/484.794aff9c.js"><link rel="prefetch" href="/assets/js/485.3e6ef3cb.js"><link rel="prefetch" href="/assets/js/486.fc20eb22.js"><link rel="prefetch" href="/assets/js/487.2a4f7d47.js"><link rel="prefetch" href="/assets/js/488.24ba9af5.js"><link rel="prefetch" href="/assets/js/489.d451928e.js"><link rel="prefetch" href="/assets/js/49.bd70c59c.js"><link rel="prefetch" href="/assets/js/490.d83e4fc7.js"><link rel="prefetch" href="/assets/js/491.0210a738.js"><link rel="prefetch" href="/assets/js/492.3a69cd85.js"><link rel="prefetch" href="/assets/js/493.89d2920f.js"><link rel="prefetch" href="/assets/js/494.b7d1c15e.js"><link rel="prefetch" href="/assets/js/495.7ccfe17f.js"><link rel="prefetch" href="/assets/js/496.0d6c912a.js"><link rel="prefetch" href="/assets/js/497.087ca2c6.js"><link rel="prefetch" href="/assets/js/498.f2b3c894.js"><link rel="prefetch" href="/assets/js/499.e741f312.js"><link rel="prefetch" href="/assets/js/5.405f2620.js"><link rel="prefetch" href="/assets/js/50.9df07553.js"><link rel="prefetch" href="/assets/js/500.cb9babb9.js"><link rel="prefetch" href="/assets/js/501.63a859b6.js"><link rel="prefetch" href="/assets/js/502.f346b273.js"><link rel="prefetch" href="/assets/js/503.cdcd3de3.js"><link rel="prefetch" href="/assets/js/504.e83ec450.js"><link rel="prefetch" href="/assets/js/505.95f18293.js"><link rel="prefetch" href="/assets/js/506.02060a3c.js"><link rel="prefetch" href="/assets/js/507.859d6ae4.js"><link rel="prefetch" href="/assets/js/508.9724d886.js"><link rel="prefetch" href="/assets/js/509.e17dd53e.js"><link rel="prefetch" href="/assets/js/51.3dfc6350.js"><link rel="prefetch" href="/assets/js/510.ea0c942f.js"><link rel="prefetch" href="/assets/js/511.64a7f9a8.js"><link rel="prefetch" href="/assets/js/512.6cce418a.js"><link rel="prefetch" href="/assets/js/513.ea813fe8.js"><link rel="prefetch" href="/assets/js/514.10242470.js"><link rel="prefetch" href="/assets/js/515.5308bdf6.js"><link rel="prefetch" href="/assets/js/516.dfb113bc.js"><link rel="prefetch" href="/assets/js/517.96c71069.js"><link rel="prefetch" href="/assets/js/518.5594480e.js"><link rel="prefetch" href="/assets/js/519.91e848ae.js"><link rel="prefetch" href="/assets/js/52.dd230cd7.js"><link rel="prefetch" href="/assets/js/520.ebe69ce9.js"><link rel="prefetch" href="/assets/js/521.92b80342.js"><link rel="prefetch" href="/assets/js/522.6ce581ea.js"><link rel="prefetch" href="/assets/js/523.40b7f2f9.js"><link rel="prefetch" href="/assets/js/524.4ef256d3.js"><link rel="prefetch" href="/assets/js/525.19741e4a.js"><link rel="prefetch" href="/assets/js/526.e5de1675.js"><link rel="prefetch" href="/assets/js/527.9a79cd42.js"><link rel="prefetch" href="/assets/js/528.72732eb8.js"><link rel="prefetch" href="/assets/js/529.2ea03e45.js"><link rel="prefetch" href="/assets/js/53.a349c565.js"><link rel="prefetch" href="/assets/js/530.5d1103e7.js"><link rel="prefetch" href="/assets/js/531.82b032d6.js"><link rel="prefetch" href="/assets/js/532.12ee4beb.js"><link rel="prefetch" href="/assets/js/533.db9a90f7.js"><link rel="prefetch" href="/assets/js/534.fe139db4.js"><link rel="prefetch" href="/assets/js/535.056a6fbb.js"><link rel="prefetch" href="/assets/js/536.6bf85c15.js"><link rel="prefetch" href="/assets/js/537.6e2e1ccf.js"><link rel="prefetch" href="/assets/js/538.54eddb3b.js"><link rel="prefetch" href="/assets/js/539.6f00a207.js"><link rel="prefetch" href="/assets/js/54.e292b52f.js"><link rel="prefetch" href="/assets/js/540.9c956205.js"><link rel="prefetch" href="/assets/js/541.50f41228.js"><link rel="prefetch" href="/assets/js/542.a2b1879e.js"><link rel="prefetch" href="/assets/js/543.4e5e17c9.js"><link rel="prefetch" href="/assets/js/544.63d85227.js"><link rel="prefetch" href="/assets/js/545.c3923644.js"><link rel="prefetch" href="/assets/js/546.e64ad073.js"><link rel="prefetch" href="/assets/js/547.35a8752d.js"><link rel="prefetch" href="/assets/js/548.b62a1348.js"><link rel="prefetch" href="/assets/js/549.369e2ea0.js"><link rel="prefetch" href="/assets/js/55.21bb2983.js"><link rel="prefetch" href="/assets/js/550.b4632248.js"><link rel="prefetch" href="/assets/js/551.18f1879c.js"><link rel="prefetch" href="/assets/js/552.162e63cd.js"><link rel="prefetch" href="/assets/js/553.6998130e.js"><link rel="prefetch" href="/assets/js/554.89126c3d.js"><link rel="prefetch" href="/assets/js/555.a5f63b8a.js"><link rel="prefetch" href="/assets/js/556.35381cef.js"><link rel="prefetch" href="/assets/js/557.ceeecf52.js"><link rel="prefetch" href="/assets/js/558.253e6e4f.js"><link rel="prefetch" href="/assets/js/559.5cfbb773.js"><link rel="prefetch" href="/assets/js/56.5382d6b4.js"><link rel="prefetch" href="/assets/js/560.cca52f22.js"><link rel="prefetch" href="/assets/js/561.ea8d1141.js"><link rel="prefetch" href="/assets/js/562.c32e7b96.js"><link rel="prefetch" href="/assets/js/563.9bdd42e7.js"><link rel="prefetch" href="/assets/js/564.b3b87ec0.js"><link rel="prefetch" href="/assets/js/565.4be0d0f7.js"><link rel="prefetch" href="/assets/js/566.9f379d12.js"><link rel="prefetch" href="/assets/js/567.261e3181.js"><link rel="prefetch" href="/assets/js/568.4229e365.js"><link rel="prefetch" href="/assets/js/569.e662c167.js"><link rel="prefetch" href="/assets/js/57.8129f7e0.js"><link rel="prefetch" href="/assets/js/570.97ff6423.js"><link rel="prefetch" href="/assets/js/571.de1377cd.js"><link rel="prefetch" href="/assets/js/572.48b8400b.js"><link rel="prefetch" href="/assets/js/573.8251ebaf.js"><link rel="prefetch" href="/assets/js/574.ec3d6c1e.js"><link rel="prefetch" href="/assets/js/575.b0d429a1.js"><link rel="prefetch" href="/assets/js/576.98ce9170.js"><link rel="prefetch" href="/assets/js/577.85fc2017.js"><link rel="prefetch" href="/assets/js/578.1393ac7f.js"><link rel="prefetch" href="/assets/js/579.1340e178.js"><link rel="prefetch" href="/assets/js/58.85ac2740.js"><link rel="prefetch" href="/assets/js/580.a5979445.js"><link rel="prefetch" href="/assets/js/581.effdc269.js"><link rel="prefetch" href="/assets/js/582.13276063.js"><link rel="prefetch" href="/assets/js/583.357a2443.js"><link rel="prefetch" href="/assets/js/584.338ef731.js"><link rel="prefetch" href="/assets/js/585.87932741.js"><link rel="prefetch" href="/assets/js/586.b1d6e000.js"><link rel="prefetch" href="/assets/js/587.ed5b8377.js"><link rel="prefetch" href="/assets/js/588.16d2c418.js"><link rel="prefetch" href="/assets/js/589.c96fd7fa.js"><link rel="prefetch" href="/assets/js/59.0b225757.js"><link rel="prefetch" href="/assets/js/590.1a06b2a0.js"><link rel="prefetch" href="/assets/js/591.0efd886c.js"><link rel="prefetch" href="/assets/js/592.b22d0ef5.js"><link rel="prefetch" href="/assets/js/593.84ed6ebe.js"><link rel="prefetch" href="/assets/js/594.cd721b88.js"><link rel="prefetch" href="/assets/js/595.2400817a.js"><link rel="prefetch" href="/assets/js/596.f2c512d1.js"><link rel="prefetch" href="/assets/js/597.df10ec57.js"><link rel="prefetch" href="/assets/js/598.61ef6a7d.js"><link rel="prefetch" href="/assets/js/599.0bebb562.js"><link rel="prefetch" href="/assets/js/6.29d112b1.js"><link rel="prefetch" href="/assets/js/60.3bbab51d.js"><link rel="prefetch" href="/assets/js/600.1ea7596f.js"><link rel="prefetch" href="/assets/js/601.f2642bb3.js"><link rel="prefetch" href="/assets/js/602.400cc987.js"><link rel="prefetch" href="/assets/js/603.db77d173.js"><link rel="prefetch" href="/assets/js/604.0ffa30ae.js"><link rel="prefetch" href="/assets/js/605.32ca9607.js"><link rel="prefetch" href="/assets/js/606.8c1e5683.js"><link rel="prefetch" href="/assets/js/607.9c9463ef.js"><link rel="prefetch" href="/assets/js/608.d5efa77e.js"><link rel="prefetch" href="/assets/js/609.5bbffb7d.js"><link rel="prefetch" href="/assets/js/61.f7301486.js"><link rel="prefetch" href="/assets/js/610.5b0fc9da.js"><link rel="prefetch" href="/assets/js/612.b0788f43.js"><link rel="prefetch" href="/assets/js/613.49511e65.js"><link rel="prefetch" href="/assets/js/614.fae3eacf.js"><link rel="prefetch" href="/assets/js/615.359e5899.js"><link rel="prefetch" href="/assets/js/616.905132f4.js"><link rel="prefetch" href="/assets/js/617.6c8c594e.js"><link rel="prefetch" href="/assets/js/618.6ac4f3ff.js"><link rel="prefetch" href="/assets/js/619.411a0c14.js"><link rel="prefetch" href="/assets/js/62.9aeede84.js"><link rel="prefetch" href="/assets/js/620.56155724.js"><link rel="prefetch" href="/assets/js/621.149d7933.js"><link rel="prefetch" href="/assets/js/622.f0c9bc08.js"><link rel="prefetch" href="/assets/js/623.e0989fbe.js"><link rel="prefetch" href="/assets/js/624.80b1f6a9.js"><link rel="prefetch" href="/assets/js/625.a0a392c4.js"><link rel="prefetch" href="/assets/js/626.56fd4e8a.js"><link rel="prefetch" href="/assets/js/627.264e7313.js"><link rel="prefetch" href="/assets/js/628.7a868b19.js"><link rel="prefetch" href="/assets/js/629.e7e15da1.js"><link rel="prefetch" href="/assets/js/63.4df55c8b.js"><link rel="prefetch" href="/assets/js/630.998c9b61.js"><link rel="prefetch" href="/assets/js/631.69aa049c.js"><link rel="prefetch" href="/assets/js/632.da3882c1.js"><link rel="prefetch" href="/assets/js/633.0d49adf0.js"><link rel="prefetch" href="/assets/js/634.f9984ede.js"><link rel="prefetch" href="/assets/js/635.f0439f65.js"><link rel="prefetch" href="/assets/js/636.54de4194.js"><link rel="prefetch" href="/assets/js/637.55d1c226.js"><link rel="prefetch" href="/assets/js/638.2a9a510f.js"><link rel="prefetch" href="/assets/js/639.8bec360e.js"><link rel="prefetch" href="/assets/js/64.7f3e5e81.js"><link rel="prefetch" href="/assets/js/640.30d7f96e.js"><link rel="prefetch" href="/assets/js/641.68100098.js"><link rel="prefetch" href="/assets/js/642.4b793817.js"><link rel="prefetch" href="/assets/js/643.d86a81ea.js"><link rel="prefetch" href="/assets/js/644.76327ea2.js"><link rel="prefetch" href="/assets/js/645.0ac6a923.js"><link rel="prefetch" href="/assets/js/646.cd92f728.js"><link rel="prefetch" href="/assets/js/647.f2c624e1.js"><link rel="prefetch" href="/assets/js/648.c8f3b955.js"><link rel="prefetch" href="/assets/js/649.6370753b.js"><link rel="prefetch" href="/assets/js/65.2beeae9b.js"><link rel="prefetch" href="/assets/js/650.afe31909.js"><link rel="prefetch" href="/assets/js/651.87971ec0.js"><link rel="prefetch" href="/assets/js/652.0adf10a6.js"><link rel="prefetch" href="/assets/js/653.1f655726.js"><link rel="prefetch" href="/assets/js/654.53e24c7c.js"><link rel="prefetch" href="/assets/js/655.c95a66ea.js"><link rel="prefetch" href="/assets/js/656.38b5a5ea.js"><link rel="prefetch" href="/assets/js/657.3167aa94.js"><link rel="prefetch" href="/assets/js/658.7c40ff62.js"><link rel="prefetch" href="/assets/js/659.5d2b9b54.js"><link rel="prefetch" href="/assets/js/66.44b214db.js"><link rel="prefetch" href="/assets/js/660.96a8da9e.js"><link rel="prefetch" href="/assets/js/661.4de3b6c1.js"><link rel="prefetch" href="/assets/js/662.7d9bf181.js"><link rel="prefetch" href="/assets/js/663.4ccaf40a.js"><link rel="prefetch" href="/assets/js/664.7ab4fa53.js"><link rel="prefetch" href="/assets/js/665.32245d26.js"><link rel="prefetch" href="/assets/js/666.e6617151.js"><link rel="prefetch" href="/assets/js/667.fb3b0547.js"><link rel="prefetch" href="/assets/js/668.3d1b2e36.js"><link rel="prefetch" href="/assets/js/669.b769905f.js"><link rel="prefetch" href="/assets/js/67.c31aaacf.js"><link rel="prefetch" href="/assets/js/670.88ed3af3.js"><link rel="prefetch" href="/assets/js/671.1aff6bfe.js"><link rel="prefetch" href="/assets/js/672.c90888f7.js"><link rel="prefetch" href="/assets/js/673.81241fdc.js"><link rel="prefetch" href="/assets/js/674.838a424d.js"><link rel="prefetch" href="/assets/js/675.603ac896.js"><link rel="prefetch" href="/assets/js/676.ff44b5dc.js"><link rel="prefetch" href="/assets/js/677.41a8087a.js"><link rel="prefetch" href="/assets/js/678.f0eb8d04.js"><link rel="prefetch" href="/assets/js/679.db78199e.js"><link rel="prefetch" href="/assets/js/68.08607c89.js"><link rel="prefetch" href="/assets/js/680.8fded9d4.js"><link rel="prefetch" href="/assets/js/681.0b019dfd.js"><link rel="prefetch" href="/assets/js/682.746e9190.js"><link rel="prefetch" href="/assets/js/683.d5c00845.js"><link rel="prefetch" href="/assets/js/684.b3207cad.js"><link rel="prefetch" href="/assets/js/685.d78f18ba.js"><link rel="prefetch" href="/assets/js/686.5aaecd19.js"><link rel="prefetch" href="/assets/js/687.821a06f4.js"><link rel="prefetch" href="/assets/js/688.8bbc1890.js"><link rel="prefetch" href="/assets/js/689.79b49e8c.js"><link rel="prefetch" href="/assets/js/69.509245d6.js"><link rel="prefetch" href="/assets/js/690.fa62f9dd.js"><link rel="prefetch" href="/assets/js/691.d3eb1a60.js"><link rel="prefetch" href="/assets/js/692.738f14bb.js"><link rel="prefetch" href="/assets/js/693.e6a497a2.js"><link rel="prefetch" href="/assets/js/694.6eea1c54.js"><link rel="prefetch" href="/assets/js/695.88e6acee.js"><link rel="prefetch" href="/assets/js/696.de10297f.js"><link rel="prefetch" href="/assets/js/697.96d04062.js"><link rel="prefetch" href="/assets/js/698.200cc84f.js"><link rel="prefetch" href="/assets/js/699.f11fc627.js"><link rel="prefetch" href="/assets/js/7.c16198b8.js"><link rel="prefetch" href="/assets/js/70.5f6285b1.js"><link rel="prefetch" href="/assets/js/700.93d48f59.js"><link rel="prefetch" href="/assets/js/701.b861f29a.js"><link rel="prefetch" href="/assets/js/702.dc82e05c.js"><link rel="prefetch" href="/assets/js/703.625ce87c.js"><link rel="prefetch" href="/assets/js/704.005a0a7c.js"><link rel="prefetch" href="/assets/js/705.16ad9230.js"><link rel="prefetch" href="/assets/js/706.4eead30a.js"><link rel="prefetch" href="/assets/js/707.730306ce.js"><link rel="prefetch" href="/assets/js/708.e37e743a.js"><link rel="prefetch" href="/assets/js/709.f2144f52.js"><link rel="prefetch" href="/assets/js/71.d5d0dae5.js"><link rel="prefetch" href="/assets/js/710.ee9d9b17.js"><link rel="prefetch" href="/assets/js/711.2813c338.js"><link rel="prefetch" href="/assets/js/712.e801bce4.js"><link rel="prefetch" href="/assets/js/713.21fc267c.js"><link rel="prefetch" href="/assets/js/714.4ec35525.js"><link rel="prefetch" href="/assets/js/715.fdc3cc84.js"><link rel="prefetch" href="/assets/js/716.324932ad.js"><link rel="prefetch" href="/assets/js/717.a072a66f.js"><link rel="prefetch" href="/assets/js/718.575e0305.js"><link rel="prefetch" href="/assets/js/719.5fdd55de.js"><link rel="prefetch" href="/assets/js/72.25648231.js"><link rel="prefetch" href="/assets/js/720.61477f23.js"><link rel="prefetch" href="/assets/js/721.c8bdab00.js"><link rel="prefetch" href="/assets/js/722.9255f385.js"><link rel="prefetch" href="/assets/js/723.f27792a4.js"><link rel="prefetch" href="/assets/js/724.cd504f88.js"><link rel="prefetch" href="/assets/js/725.55c845fa.js"><link rel="prefetch" href="/assets/js/726.bb49a9db.js"><link rel="prefetch" href="/assets/js/727.53d587fe.js"><link rel="prefetch" href="/assets/js/728.86972387.js"><link rel="prefetch" href="/assets/js/729.02fa0263.js"><link rel="prefetch" href="/assets/js/73.29902c1f.js"><link rel="prefetch" href="/assets/js/730.817156d1.js"><link rel="prefetch" href="/assets/js/731.6f5d6735.js"><link rel="prefetch" href="/assets/js/732.9a5ff781.js"><link rel="prefetch" href="/assets/js/733.bcb13916.js"><link rel="prefetch" href="/assets/js/734.11482b19.js"><link rel="prefetch" href="/assets/js/735.8c0d62f3.js"><link rel="prefetch" href="/assets/js/736.06465705.js"><link rel="prefetch" href="/assets/js/737.79741d87.js"><link rel="prefetch" href="/assets/js/738.cad12ff9.js"><link rel="prefetch" href="/assets/js/739.cb09e552.js"><link rel="prefetch" href="/assets/js/74.bcf666a0.js"><link rel="prefetch" href="/assets/js/740.029b1950.js"><link rel="prefetch" href="/assets/js/741.b937216a.js"><link rel="prefetch" href="/assets/js/742.ec02c706.js"><link rel="prefetch" href="/assets/js/743.70a96283.js"><link rel="prefetch" href="/assets/js/744.909b870c.js"><link rel="prefetch" href="/assets/js/745.80defb2d.js"><link rel="prefetch" href="/assets/js/746.fb972248.js"><link rel="prefetch" href="/assets/js/747.1a7b52fd.js"><link rel="prefetch" href="/assets/js/748.036f5d16.js"><link rel="prefetch" href="/assets/js/749.bd9a413d.js"><link rel="prefetch" href="/assets/js/75.23c5a54d.js"><link rel="prefetch" href="/assets/js/750.3f1ae8f5.js"><link rel="prefetch" href="/assets/js/751.8897bc9f.js"><link rel="prefetch" href="/assets/js/752.9b387659.js"><link rel="prefetch" href="/assets/js/753.f411ce21.js"><link rel="prefetch" href="/assets/js/754.26def684.js"><link rel="prefetch" href="/assets/js/755.923aff62.js"><link rel="prefetch" href="/assets/js/756.9965743a.js"><link rel="prefetch" href="/assets/js/757.0c6bbbfd.js"><link rel="prefetch" href="/assets/js/758.a830f8b1.js"><link rel="prefetch" href="/assets/js/759.987cad77.js"><link rel="prefetch" href="/assets/js/76.f54f3d4f.js"><link rel="prefetch" href="/assets/js/760.9f2652a0.js"><link rel="prefetch" href="/assets/js/761.df01a0ee.js"><link rel="prefetch" href="/assets/js/762.e0c05a1a.js"><link rel="prefetch" href="/assets/js/763.da8a60bd.js"><link rel="prefetch" href="/assets/js/764.9f2a2830.js"><link rel="prefetch" href="/assets/js/765.44e61161.js"><link rel="prefetch" href="/assets/js/766.cd7da8c1.js"><link rel="prefetch" href="/assets/js/767.6ea1fea2.js"><link rel="prefetch" href="/assets/js/768.91529b8f.js"><link rel="prefetch" href="/assets/js/769.194d7a3e.js"><link rel="prefetch" href="/assets/js/77.3d43a163.js"><link rel="prefetch" href="/assets/js/770.227fd5b9.js"><link rel="prefetch" href="/assets/js/771.44d5e37e.js"><link rel="prefetch" href="/assets/js/772.234d9bf6.js"><link rel="prefetch" href="/assets/js/773.ff1dfb6a.js"><link rel="prefetch" href="/assets/js/774.d401364f.js"><link rel="prefetch" href="/assets/js/775.37a7cf41.js"><link rel="prefetch" href="/assets/js/776.0cd10853.js"><link rel="prefetch" href="/assets/js/777.599a3a48.js"><link rel="prefetch" href="/assets/js/778.eef27a95.js"><link rel="prefetch" href="/assets/js/779.29351199.js"><link rel="prefetch" href="/assets/js/78.fd0780ac.js"><link rel="prefetch" href="/assets/js/780.74caed94.js"><link rel="prefetch" href="/assets/js/781.ee0fa9b5.js"><link rel="prefetch" href="/assets/js/782.7cffed09.js"><link rel="prefetch" href="/assets/js/783.7f01f518.js"><link rel="prefetch" href="/assets/js/784.5f65e3d7.js"><link rel="prefetch" href="/assets/js/785.d7e13880.js"><link rel="prefetch" href="/assets/js/786.6110d12f.js"><link rel="prefetch" href="/assets/js/787.334a5cdd.js"><link rel="prefetch" href="/assets/js/788.f261bc71.js"><link rel="prefetch" href="/assets/js/789.b6d74f7d.js"><link rel="prefetch" href="/assets/js/79.7b5d6224.js"><link rel="prefetch" href="/assets/js/790.fa948ec4.js"><link rel="prefetch" href="/assets/js/791.22080013.js"><link rel="prefetch" href="/assets/js/792.31ce806c.js"><link rel="prefetch" href="/assets/js/793.9fd0c56f.js"><link rel="prefetch" href="/assets/js/794.44a8cd9c.js"><link rel="prefetch" href="/assets/js/795.9f8346e5.js"><link rel="prefetch" href="/assets/js/796.0de9c7a1.js"><link rel="prefetch" href="/assets/js/797.83ac32a6.js"><link rel="prefetch" href="/assets/js/798.393fc81d.js"><link rel="prefetch" href="/assets/js/799.c1fb3981.js"><link rel="prefetch" href="/assets/js/8.3275ed06.js"><link rel="prefetch" href="/assets/js/80.df3f0a1f.js"><link rel="prefetch" href="/assets/js/800.2832adeb.js"><link rel="prefetch" href="/assets/js/801.04c58fc4.js"><link rel="prefetch" href="/assets/js/81.3d90ef6b.js"><link rel="prefetch" href="/assets/js/82.2d42448d.js"><link rel="prefetch" href="/assets/js/83.900b4de2.js"><link rel="prefetch" href="/assets/js/84.ff570f67.js"><link rel="prefetch" href="/assets/js/85.e3b3af39.js"><link rel="prefetch" href="/assets/js/86.17b5aedc.js"><link rel="prefetch" href="/assets/js/87.f931d1d6.js"><link rel="prefetch" href="/assets/js/88.d55863cd.js"><link rel="prefetch" href="/assets/js/89.15a9a6d7.js"><link rel="prefetch" href="/assets/js/9.04948a9d.js"><link rel="prefetch" href="/assets/js/90.22696aa9.js"><link rel="prefetch" href="/assets/js/91.f1bd8a2e.js"><link rel="prefetch" href="/assets/js/92.85733094.js"><link rel="prefetch" href="/assets/js/93.59bacfd7.js"><link rel="prefetch" href="/assets/js/94.a5f9b7a0.js"><link rel="prefetch" href="/assets/js/95.be52d65a.js"><link rel="prefetch" href="/assets/js/96.0b76ba8e.js"><link rel="prefetch" href="/assets/js/97.28183cd4.js"><link rel="prefetch" href="/assets/js/98.2d22829c.js"><link rel="prefetch" href="/assets/js/99.ed602a20.js">
    <link rel="stylesheet" href="/assets/css/0.styles.a3df589e.css">
  </head>
  <body>
    <div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><!----> <span class="site-name">AJ</span></a> <div class="links"><div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link">主页</a></div><div class="nav-item"><a href="/op/" class="nav-link">Devops</a></div><div class="nav-item"><a href="/golang/" class="nav-link">Go</a></div><div class="nav-item"><a href="/go-block/" class="nav-link">区块链</a></div><div class="nav-item"><a href="/k8s/" class="nav-link">k8s</a></div><div class="nav-item"><a href="/about.html" class="nav-link">关于我</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="更多" class="dropdown-title"><span class="title">更多</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/go-learning/" class="nav-link">go-learning</a></li><li class="dropdown-item"><!----> <a href="/post/flutter-guide/" class="nav-link">flutter</a></li><li class="dropdown-item"><!----> <a href="/mysql/" class="nav-link router-link-active">mysql</a></li><li class="dropdown-item"><!----> <a href="/python/" class="nav-link">python</a></li></ul></div></div> <a href="https://github.com/ChinaArJun" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></nav></div></header> <div class="sidebar-mask"></div> <aside class="sidebar"><nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link">主页</a></div><div class="nav-item"><a href="/op/" class="nav-link">Devops</a></div><div class="nav-item"><a href="/golang/" class="nav-link">Go</a></div><div class="nav-item"><a href="/go-block/" class="nav-link">区块链</a></div><div class="nav-item"><a href="/k8s/" class="nav-link">k8s</a></div><div class="nav-item"><a href="/about.html" class="nav-link">关于我</a></div><div class="nav-item"><div class="dropdown-wrapper"><button type="button" aria-label="更多" class="dropdown-title"><span class="title">更多</span> <span class="arrow right"></span></button> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/go-learning/" class="nav-link">go-learning</a></li><li class="dropdown-item"><!----> <a href="/post/flutter-guide/" class="nav-link">flutter</a></li><li class="dropdown-item"><!----> <a href="/mysql/" class="nav-link router-link-active">mysql</a></li><li class="dropdown-item"><!----> <a href="/python/" class="nav-link">python</a></li></ul></div></div> <a href="https://github.com/ChinaArJun" target="_blank" rel="noopener noreferrer" class="repo-link">
    GitHub
    <svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg></a></nav> <div></div> <div style="padding-left:1.5rem;"><div></div></div> <ul class="sidebar-links"><li><a href="/mysql/" aria-current="page" class="sidebar-link">SQL 必知必会</a></li><li><a href="/mysql/%E4%BB%8E%E6%A0%B9%E5%84%BF%E4%B8%8A%E7%90%86%E8%A7%A3%20MySQL/" aria-current="page" class="sidebar-link">从根儿上理解 MySQL</a></li><li><a href="/mysql/01.MySQL基本操作.html" class="sidebar-link">1、MySQL基本操作</a></li><li><a href="/mysql/02.列类型和数据完整性.html" class="sidebar-link">2、列类型和数据完整性</a></li><li><a href="/mysql/03.数据库设计与查询语句.html" class="sidebar-link">3、  数据库设计与查询语句</a></li><li><a href="/mysql/04.视图、事务、索引、函数、GO连接MySQL.html" class="sidebar-link">4-视图、事务、索引、函数、GO连接MySQL</a></li><li><a href="/mysql/MySQL高级知识-第1章.html" class="sidebar-link">MySQL高级知识-第1章</a></li><li><a href="/mysql/MySQL高级知识-第2章.html" class="sidebar-link">MySQL高级知识-第2章</a></li><li><a href="/mysql/MySQL高级知识-第3章.html" class="sidebar-link">MySQL高级知识-第3章</a></li><li><a href="/mysql/MySQL高级知识-第4章.html" class="sidebar-link">MySQL高级知识-第4章</a></li></ul> </aside> <!----> <!----> <main class="page"><div class="theme-default-content" style="margin-bottom:-5rem;"><div class="bar"><div class="bar-intro"><div class="text">
      流逝的是岁月，不变的是情怀.
        </div> <div class="text">
      坚持学习，是为了成就更好的自己. <br></div> <div>公众号[中关村程序员]</div></div></div> <!----></div> <div class="theme-default-content content__default"><h1 id="redo日志（上）"><a href="#redo日志（上）" class="header-anchor">#</a> redo日志（上）</h1> <p>标签： MySQL是怎样运行的</p> <hr> <h2 id="事先说明"><a href="#事先说明" class="header-anchor">#</a> 事先说明</h2> <p>本文以及接下来的几篇文章将会频繁的使用到我们前边唠叨的<code>InnoDB</code>记录行格式、页面格式、索引原理、表空间的组成等各种基础知识，如果大家对这些东西理解的不透彻，那么阅读下边的文字可能会有些吃力，为保证您的阅读体验，请确保自己已经掌握了我前边唠叨的这些知识。</p> <h2 id="redo日志是个啥"><a href="#redo日志是个啥" class="header-anchor">#</a> redo日志是个啥</h2> <p>我们知道<code>InnoDB</code>存储引擎是以页为单位来管理存储空间的，我们进行的增删改查操作其实本质上都是在访问页面（包括读页面、写页面、创建新页面等操作）。我们前边唠叨<code>Buffer Pool</code>的时候说过，在真正访问页面之前，需要把在磁盘上的页缓存到内存中的<code>Buffer Pool</code>之后才可以访问。但是在唠叨事务的时候又强调过一个称之为<code>持久性</code>的特性，就是说对于一个已经提交的事务，在事务提交后即使系统发生了崩溃，这个事务对数据库中所做的更改也不能丢失。但是如果我们只在内存的<code>Buffer Pool</code>中修改了页面，假设在事务提交后突然发生了某个故障，导致内存中的数据都失效了，那么这个已经提交了的事务对数据库中所做的更改也就跟着丢失了，这是我们所不能忍受的（想想ATM机已经提示狗哥转账成功，但之后由于服务器出现故障，重启之后猫爷发现自己没收到钱，猫爷就被砍死了）。那么如何保证这个<code>持久性</code>呢？一个很简单的做法就是<span style="color:red;">在事务提交完成之前把该事务所修改的所有页面都刷新到磁盘</span>，但是这个简单粗暴的做法有些问题：</p> <ul><li><p>刷新一个完整的数据页太浪费了</p> <p>有时候我们仅仅修改了某个页面中的一个字节，但是我们知道在<code>InnoDB</code>中是以页为单位来进行磁盘IO的，也就是说我们在该事务提交时不得不将一个完整的页面从内存中刷新到磁盘，我们又知道一个页面默认是16KB大小，只修改一个字节就要刷新16KB的数据到磁盘上显然是太浪费了。</p></li> <li><p>随机IO刷起来比较慢</p> <p>一个事务可能包含很多语句，即使是一条语句也可能修改许多页面，倒霉催的是该事务修改的这些页面可能并不相邻，这就意味着在将某个事务修改的<code>Buffer Pool</code>中的页面刷新到磁盘时，需要进行很多的随机IO，随机IO比顺序IO要慢，尤其对于传统的机械硬盘来说。</p></li></ul> <p>咋办呢？再次回到我们的初心：<span style="color:red;">我们只是想让已经提交了的事务对数据库中数据所做的修改永久生效，即使后来系统崩溃，在重启后也能把这种修改恢复出来</span>。所以我们其实没有必要在每次事务提交时就把该事务在内存中修改过的全部页面刷新到磁盘，只需要<span style="color:red;">把修改了哪些东西记录一下就好</span>，比方说某个事务将系统表空间中的第100号页面中偏移量为1000处的那个字节的值<code>1</code>改成<code>2</code>我们只需要记录一下：</p> <blockquote><p>将第0号表空间的100号页面的偏移量为1000处的值更新为<code>2</code>。</p></blockquote> <p>这样我们在事务提交时，把上述内容刷新到磁盘中，即使之后系统崩溃了，重启之后只要按照上述内容所记录的步骤重新更新一下数据页，那么该事务对数据库中所做的修改又可以被恢复出来，也就意味着满足<code>持久性</code>的要求。因为在系统奔溃重启时需要按照上述内容所记录的步骤重新更新数据页，所以上述内容也被称之为<code>重做日志</code>，英文名为<code>redo log</code>，我们也可以土洋结合，称之为<code>redo日志</code>。与在事务提交时将所有修改过的内存中的页面刷新到磁盘中相比，只将该事务执行过程中产生的<code>redo</code>日志刷新到磁盘的好处如下：</p> <ul><li><p><code>redo</code>日志占用的空间非常小</p> <p>存储表空间ID、页号、偏移量以及需要更新的值所需的存储空间是很小的，关于<code>redo</code>日志的格式我们稍后会详细唠叨，现在只要知道一条<code>redo</code>日志占用的空间不是很大就好了。</p></li> <li><p><code>redo</code>日志是顺序写入磁盘的</p> <p>在执行事务的过程中，每执行一条语句，就可能产生若干条<code>redo</code>日志，这些日志是按照产生的顺序写入磁盘的，也就是使用顺序IO。</p></li></ul> <h2 id="redo日志格式"><a href="#redo日志格式" class="header-anchor">#</a> redo日志格式</h2> <p>通过上边的内容我们知道，<code>redo</code>日志本质上只是<span style="color:red;">记录了一下事务对数据库做了哪些修改</span>。 设计<code>InnoDB</code>的大叔们针对事务对数据库的不同修改场景定义了多种类型的<code>redo</code>日志，但是绝大部分类型的<code>redo</code>日志都有下边这种通用的结构：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/1694892fdec61898?w=982&amp;h=253&amp;f=png&amp;s=32063" alt="image_1d36k7d3412oo1c0qcuuben12l79.png-31.3kB"></p> <p>各个部分的详细释义如下：</p> <ul><li><p><code>type</code>：该条<code>redo</code>日志的类型。</p> <p>在<code>MySQL 5.7.21</code>这个版本中，设计<code>InnoDB</code>的大叔一共为<code>redo</code>日志设计了53种不同的类型，稍后会详细介绍不同类型的<code>redo</code>日志。</p></li> <li><p><code>space ID</code>：表空间ID。</p></li> <li><p><code>page number</code>：页号。</p></li> <li><p><code>data</code>：该条<code>redo</code>日志的具体内容。</p></li></ul> <h3 id="简单的redo日志类型"><a href="#简单的redo日志类型" class="header-anchor">#</a> 简单的redo日志类型</h3> <p>我们前边介绍<code>InnoDB</code>的记录行格式的时候说过，如果我们没有为某个表显式的定义主键，并且表中也没有定义<code>Unique</code>键，那么<code>InnoDB</code>会自动的为表添加一个称之为<code>row_id</code>的隐藏列作为主键。为这个<code>row_id</code>隐藏列赋值的方式如下：</p> <ul><li><p>服务器会在内存中维护一个全局变量，每当向某个包含隐藏的<code>row_id</code>列的表中插入一条记录时，就会把该变量的值当作新记录的<code>row_id</code>列的值，并且把该变量自增1。</p></li> <li><p>每当这个变量的值为256的倍数时，就会将该变量的值刷新到系统表空间的页号为<code>7</code>的页面中一个称之为<code>Max Row ID</code>的属性处（我们前边介绍表空间结构时详细说过）。</p></li> <li><p>当系统启动时，会将上边提到的<code>Max Row ID</code>属性加载到内存中，将该值加上256之后赋值给我们前边提到的全局变量（因为在上次关机时该全局变量的值可能大于<code>Max Row ID</code>属性值）。</p></li></ul> <p>这个<code>Max Row ID</code>属性占用的存储空间是8个字节，当某个事务向某个包含<code>row_id</code>隐藏列的表插入一条记录，并且为该记录分配的<code>row_id</code>值为256的倍数时，就会向系统表空间页号为7的页面的相应偏移量处写入8个字节的值。但是我们要知道，这个写入实际上是在<code>Buffer Pool</code>中完成的，我们需要为这个页面的修改记录一条<code>redo</code>日志，以便在系统奔溃后能将已经提交的该事务对该页面所做的修改恢复出来。这种情况下对页面的修改是极其简单的，<code>redo</code>日志中只需要<span style="color:red;">记录一下在某个页面的某个偏移量处修改了几个字节的值，具体被修改的内容是啥就好了</span>，设计<code>InnoDB</code>的大叔把这种极其简单的<code>redo</code>日志称之为<code>物理日志</code>，并且根据在页面中写入数据的多少划分了几种不同的<code>redo</code>日志类型：</p> <ul><li><p><code>MLOG_1BYTE</code>（<code>type</code>字段对应的十进制数字为<code>1</code>）：表示在页面的某个偏移量处写入1个字节的<code>redo</code>日志类型。</p></li> <li><p><code>MLOG_2BYTE</code>（<code>type</code>字段对应的十进制数字为<code>2</code>）：表示在页面的某个偏移量处写入2个字节的<code>redo</code>日志类型。</p></li> <li><p><code>MLOG_4BYTE</code>（<code>type</code>字段对应的十进制数字为<code>4</code>）：表示在页面的某个偏移量处写入4个字节的<code>redo</code>日志类型。</p></li> <li><p><code>MLOG_8BYTE</code>（<code>type</code>字段对应的十进制数字为<code>8</code>）：表示在页面的某个偏移量处写入8个字节的<code>redo</code>日志类型。</p></li> <li><p><code>MLOG_WRITE_STRING</code>（<code>type</code>字段对应的十进制数字为<code>30</code>）：表示在页面的某个偏移量处写入一串数据。</p></li></ul> <p>我们上边提到的<code>Max Row ID</code>属性实际占用8个字节的存储空间，所以在修改页面中的该属性时，会记录一条类型为<code>MLOG_8BYTE</code>的<code>redo</code>日志，<code>MLOG_8BYTE</code>的<code>redo</code>日志结构如下所示：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/1694892fdf053082?w=839&amp;h=291&amp;f=png&amp;s=43606" alt="image_1d3fv01mv3jd7m719rpmn2jcsp.png-42.6kB"></p> <p>其余<code>MLOG_1BYTE</code>、<code>MLOG_2BYTE</code>、<code>MLOG_4BYTE</code>类型的<code>redo</code>日志结构和<code>MLOG_8BYTE</code>的类似，只不过具体数据中包含对应个字节的数据罢了。<code>MLOG_WRITE_STRING</code>类型的<code>redo</code>日志表示写入一串数据，但是因为不能确定写入的具体数据占用多少字节，所以需要在日志结构中添加一个<code>len</code>字段：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/1694892fdf3da823?w=878&amp;h=299&amp;f=png&amp;s=48358" alt="image_1d3fv8at819jh1m7m1sfb1donvmu16.png-47.2kB"></p> <div class="language-! extra-class"><pre class="language-text"><code>小贴士：

只要将MLOG_WRITE_STRING类型的redo日志的len字段填充上1、2、4、8这些数字，就可以分别替代MLOG_1BYTE、MLOG_2BYTE、MLOG_4BYTE、MLOG_8BYTE这些类型的redo日志，为啥还要多此一举设计这么多类型呢？还不是因为省空间啊，能不写len字段就不写len字段，省一个字节算一个字节。
</code></pre></div><h3 id="复杂一些的redo日志类型"><a href="#复杂一些的redo日志类型" class="header-anchor">#</a> 复杂一些的redo日志类型</h3> <p>有时候执行一条语句会修改非常多的页面，包括系统数据页面和用户数据页面（用户数据指的就是聚簇索引和二级索引对应的<code>B+</code>树）。以一条<code>INSERT</code>语句为例，它除了要向<code>B+</code>树的页面中插入数据，也可能更新系统数据<code>Max Row ID</code>的值，不过对于我们用户来说，平时更关心的是语句对<code>B+</code>树所做更新：</p> <ul><li><p>表中包含多少个索引，一条<code>INSERT</code>语句就可能更新多少棵<code>B+</code>树。</p></li> <li><p>针对某一棵<code>B+</code>树来说，既可能更新叶子节点页面，也可能更新内节点页面，也可能创建新的页面（在该记录插入的叶子节点的剩余空间比较少，不足以存放该记录时，会进行页面的分裂，在内节点页面中添加<code>目录项记录</code>）。</p></li></ul> <p>在语句执行过程中，<code>INSERT</code>语句对所有页面的修改都得保存到<code>redo</code>日志中去。这句话说的比较轻巧，做起来可就比较麻烦了，比方说将记录插入到聚簇索引中时，如果定位到的叶子节点的剩余空间足够存储该记录时，那么只更新该叶子节点页面就好，那么只记录一条<code>MLOG_WRITE_STRING</code>类型的<code>redo</code>日志，表明在页面的某个偏移量处增加了哪些数据就好了么？那就too young too naive了～ 别忘了一个数据页中除了存储实际的记录之后，还有什么<code>File Header</code>、<code>Page Header</code>、<code>Page Directory</code>等等部分（在唠叨数据页的章节有详细讲解），所以每往叶子节点代表的数据页里插入一条记录时，还有其他很多地方会跟着更新，比如说：</p> <ul><li><p>可能更新<code>Page Directory</code>中的槽信息。</p></li> <li><p><code>Page Header</code>中的各种页面统计信息，比如<code>PAGE_N_DIR_SLOTS</code>表示的槽数量可能会更改，<code>PAGE_HEAP_TOP</code>代表的还未使用的空间最小地址可能会更改，<code>PAGE_N_HEAP</code>代表的本页面中的记录数量可能会更改，吧啦吧啦，各种信息都可能会被修改。</p></li> <li><p>我们知道在数据页里的记录是按照索引列从小到大的顺序组成一个单向链表的，每插入一条记录，还需要更新上一条记录的记录头信息中的<code>next_record</code>属性来维护这个单向链表。</p></li> <li><p>还有别的吧啦吧啦的更新的地方，就不一一唠叨了...</p></li></ul> <p>画一个简易的示意图就像是这样：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/1694892fdfa7d8ce?w=1127&amp;h=524&amp;f=png&amp;s=68863" alt="image_1d3gv4i7vtsirf81ikl1q2140n2g.png-67.2kB"></p> <p>说了这么多，就是想表达：<span style="color:red;">把一条记录插入到一个页面时需要更改的地方非常多</span>。这时我们如果使用上边介绍的简单的物理<code>redo</code>日志来记录这些修改时，可以有两种解决方案：</p> <ul><li><p>方案一：在每个修改的地方都记录一条<code>redo</code>日志。</p> <p>也就是如上图所示，有多少个加粗的块，就写多少条物理<code>redo</code>日志。这样子记录<code>redo</code>日志的缺点是显而易见的，因为被修改的地方是在太多了，可能记录的<code>redo</code>日志占用的空间都比整个页面占用的空间都多了～</p></li> <li><p>方案二：将整个页面的<code>第一个被修改的字节</code>到<code>最后一个修改的字节</code>之间所有的数据当成是一条物理<code>redo</code>日志中的具体数据。</p> <p>从图中也可以看出来，<code>第一个被修改的字节</code>到<code>最后一个修改的字节</code>之间仍然有许多没有修改过的数据，我们把这些没有修改的数据也加入到<code>redo</code>日志中去岂不是太浪费了～</p></li></ul> <p>正因为上述两种使用物理<code>redo</code>日志的方式来记录某个页面中做了哪些修改比较浪费，设计<code>InnoDB</code>的大叔本着勤俭节约的初心，提出了一些新的<code>redo</code>日志类型，比如：</p> <ul><li><p><code>MLOG_REC_INSERT</code>（对应的十进制数字为<code>9</code>）：表示插入一条使用非紧凑行格式的记录时的<code>redo</code>日志类型。</p></li> <li><p><code>MLOG_COMP_REC_INSERT</code>（对应的十进制数字为<code>38</code>）：表示插入一条使用紧凑行格式的记录时的<code>redo</code>日志类型。</p></li></ul> <div class="language-! extra-class"><pre class="language-text"><code>小贴士：

Redundant是一种比较原始的行格式，它就是非紧凑的。而Compact、Dynamic以及Compressed行格式是较新的行格式，它们是紧凑的（占用更小的存储空间）。
</code></pre></div><ul><li><p><code>MLOG_COMP_PAGE_CREATE</code>（<code>type</code>字段对应的十进制数字为<code>58</code>）：表示创建一个存储紧凑行格式记录的页面的<code>redo</code>日志类型。</p></li> <li><p><code>MLOG_COMP_REC_DELETE</code>（<code>type</code>字段对应的十进制数字为<code>42</code>）：表示删除一条使用紧凑行格式记录的<code>redo</code>日志类型。</p></li> <li><p><code>MLOG_COMP_LIST_START_DELETE</code>（<code>type</code>字段对应的十进制数字为<code>44</code>）：表示从某条给定记录开始删除页面中的一系列使用紧凑行格式记录的<code>redo</code>日志类型。</p></li> <li><p><code>MLOG_COMP_LIST_END_DELETE</code>（<code>type</code>字段对应的十进制数字为<code>43</code>）：与<code>MLOG_COMP_LIST_START_DELETE</code>类型的<code>redo</code>日志呼应，表示删除一系列记录直到<code>MLOG_COMP_LIST_END_DELETE</code>类型的<code>redo</code>日志对应的记录为止。</p></li></ul> <div class="language-! extra-class"><pre class="language-text"><code>小贴士：

我们前边唠叨InnoDB数据页格式的时候重点强调过，数据页中的记录是按照索引列大小的顺序组成单向链表的。有时候我们会有删除索引列的值在某个区间范围内的所有记录的需求，这时候如果我们每删除一条记录就写一条redo日志的话，效率可能有点低，所以提出MLOG_COMP_LIST_START_DELETE和MLOG_COMP_LIST_END_DELETE类型的redo日志，可以很大程度上减少redo日志的条数。
</code></pre></div><ul><li><p><code>MLOG_ZIP_PAGE_COMPRESS</code>（<code>type</code>字段对应的十进制数字为<code>51</code>）：表示压缩一个数据页的<code>redo</code>日志类型。</p></li> <li><p>······还有很多很多种类型，这就不列举了，等用到再说哈～</p></li></ul> <p>这些类型的<code>redo</code>日志既包含<code>物理</code>层面的意思，也包含<code>逻辑</code>层面的意思，具体指：</p> <ul><li><p>物理层面看，这些日志都指明了对哪个表空间的哪个页进行了修改。</p></li> <li><p>逻辑层面看，在系统奔溃重启时，并不能直接根据这些日志里的记载，将页面内的某个偏移量处恢复成某个数据，而是需要调用一些事先准备好的函数，执行完这些函数后才可以将页面恢复成系统奔溃前的样子。</p></li></ul> <p>大家看到这可能有些懵逼，我们还是以类型为<code>MLOG_COMP_REC_INSERT</code>这个代表插入一条使用紧凑行格式的记录时的<code>redo</code>日志为例来理解一下我们上边所说的<code>物理</code>层面和<code>逻辑</code>层面到底是个啥意思。废话少说，直接看一下这个类型为<code>MLOG_COMP_REC_INSERT</code>的<code>redo</code>日志的结构（由于字段太多了，我们把它们竖着看效果好些）：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/1694892fe02553d0?w=565&amp;h=625&amp;f=png&amp;s=87737" alt="image_1d3bn8tsq1ssp1nmdks8kdr17e31t.png-85.7kB"></p> <p>这个类型为<code>MLOG_COMP_REC_INSERT</code>的<code>redo</code>日志结构有几个地方需要大家注意：</p> <ul><li><p>我们前边在唠叨索引的时候说过，在一个数据页里，不论是叶子节点还是非叶子节点，记录都是按照索引列从小到大的顺序排序的。对于二级索引来说，当索引列的值相同时，记录还需要按照主键值进行排序。图中<code>n_uniques</code>的值的含义是在一条记录中，需要几个字段的值才能确保记录的唯一性，这样当插入一条记录时就可以按照记录的前<code>n_uniques</code>个字段进行排序。对于聚簇索引来说，<code>n_uniques</code>的值为主键的列数，对于其他二级索引来说，该值为索引列数+主键列数。这里需要注意的是，唯一二级索引的值可能为<code>NULL</code>，所以该值仍然为索引列数+主键列数。</p></li> <li><p><code>field1_len ~ fieldn_len</code>代表着该记录若干个字段占用存储空间的大小，需要注意的是，这里不管该字段的类型是固定长度大小的（比如<code>INT</code>），还是可变长度大小（比如<code>VARCHAR(M)</code>）的，该字段占用的大小始终要写入<code>redo</code>日志中。</p></li> <li><p><code>offset</code>代表的是该记录的前一条记录在页面中的地址。为啥要记录前一条记录的地址呢？这是因为每向数据页插入一条记录，都需要修改该页面中维护的记录链表，每条记录的<code>记录头信息</code>中都包含一个称为<code>next_record</code>的属性，所以在插入新记录时，需要修改前一条记录的<code>next_record</code>属性。</p></li> <li><p>我们知道一条记录其实由<code>额外信息</code>和<code>真实数据</code>这两部分组成，这两个部分的总大小就是一条记录占用存储空间的总大小。通过<code>end_seg_len</code>的值可以间接的计算出一条记录占用存储空间的总大小，为啥不直接存储一条记录占用存储空间的总大小呢？这是因为写<code>redo</code>日志是一个非常频繁的操作，设计<code>InnoDB</code>的大叔想方设法想减小<code>redo</code>日志本身占用的存储空间大小，所以想了一些弯弯绕的算法来实现这个目标，<code>end_seg_len</code>这个字段就是为了节省<code>redo</code>日志存储空间而提出来的。至于具体设计<code>InnoDB</code>的大叔到底是用了什么神奇魔法减小<code>redo</code>日志大小的，我们这就不多唠叨了，因为的确有那么一丢丢小复杂，说清楚还是有一点点麻烦的，而且说明白了也没啥用。</p></li> <li><p><code>mismatch_index</code>的值也是为了节省<code>redo</code>日志的大小而设立的，大家可以忽略。</p></li></ul> <p>很显然这个类型为<code>MLOG_COMP_REC_INSERT</code>的<code>redo</code>日志并没有记录<code>PAGE_N_DIR_SLOTS</code>的值修改为了啥，<code>PAGE_HEAP_TOP</code>的值修改为了啥，<code>PAGE_N_HEAP</code>的值修改为了啥等等这些信息，而只是把在本页面中插入一条记录所有必备的要素记了下来，之后系统奔溃重启时，服务器会调用相关向某个页面插入一条记录的那个函数，而<code>redo</code>日志中的那些数据就可以被当成是调用这个函数所需的参数，在调用完该函数后，页面中的<code>PAGE_N_DIR_SLOTS</code>、<code>PAGE_HEAP_TOP</code>、<code>PAGE_N_HEAP</code>等等的值也就都被恢复到系统奔溃前的样子了。这就是所谓的<code>逻辑</code>日志的意思。</p> <h3 id="redo日志格式小结"><a href="#redo日志格式小结" class="header-anchor">#</a> redo日志格式小结</h3> <p>虽然上边说了一大堆关于<code>redo</code>日志格式的内容，但是如果你不是为了写一个解析<code>redo</code>日志的工具或者自己开发一套<code>redo</code>日志系统的话，那就没必要把<code>InnoDB</code>中的各种类型的<code>redo</code>日志格式都研究的透透的，没那个必要。上边我只是象征性的介绍了几种类型的<code>redo</code>日志格式，目的还是想让大家明白：<span style="color:red;">redo日志会把事务在执行过程中对数据库所做的所有修改都记录下来，在之后系统奔溃重启后可以把事务所做的任何修改都恢复出来</span>。</p> <div class="language-! extra-class"><pre class="language-text"><code>小贴士：

为了节省redo日志占用的存储空间大小，设计InnoDB的大叔对redo日志中的某些数据还可能进行压缩处理，比方说spacd ID和page number一般占用4个字节来存储，但是经过压缩后，可能使用更小的空间来存储。具体压缩算法就不唠叨了。
</code></pre></div><h2 id="mini-transaction"><a href="#mini-transaction" class="header-anchor">#</a> Mini-Transaction</h2> <h3 id="以组的形式写入redo日志"><a href="#以组的形式写入redo日志" class="header-anchor">#</a> 以组的形式写入redo日志</h3> <p>语句在执行过程中可能修改若干个页面。比如我们前边说的一条<code>INSERT</code>语句可能修改系统表空间页号为<code>7</code>的页面的<code>Max Row ID</code>属性（当然也可能更新别的系统页面，只不过我们没有都列举出来而已），还会更新聚簇索引和二级索引对应<code>B+</code>树中的页面。由于对这些页面的更改都发生在<code>Buffer Pool</code>中，所以在修改完页面之后，需要记录一下相应的<code>redo</code>日志。在执行语句的过程中产生的<code>redo</code>日志被设计<code>InnoDB</code>的大叔人为的划分成了若干个不可分割的组，比如：</p> <ul><li><p>更新<code>Max Row ID</code>属性时产生的<code>redo</code>日志是不可分割的。</p></li> <li><p>向聚簇索引对应<code>B+</code>树的页面中插入一条记录时产生的<code>redo</code>日志是不可分割的。</p></li> <li><p>向某个二级索引对应<code>B+</code>树的页面中插入一条记录时产生的<code>redo</code>日志是不可分割的。</p></li> <li><p>还有其他的一些对页面的访问操作时产生的<code>redo</code>日志是不可分割的。。。</p></li></ul> <p>怎么理解这个<code>不可分割</code>的意思呢？我们以向某个索引对应的<code>B+</code>树插入一条记录为例，在向<code>B+</code>树中插入这条记录之前，需要先定位到这条记录应该被插入到哪个叶子节点代表的数据页中，定位到具体的数据页之后，有两种可能的情况：</p> <ul><li><p>情况一：该数据页的剩余的空闲空间充足，足够容纳这一条待插入记录，那么事情很简单，直接把记录插入到这个数据页中，记录一条类型为<code>MLOG_COMP_REC_INSERT</code>的<code>redo</code>日志就好了，我们把这种情况称之为<code>乐观插入</code>。假如某个索引对应的<code>B+</code>树长这样：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/1694892fe05a2603?w=722&amp;h=458&amp;f=png&amp;s=31490" alt="image_1d4fc7b6b1ftt16ji11as4a63h23.png-30.8kB"></p> <p>现在我们要插入一条键值为<code>10</code>的记录，很显然需要被插入到<code>页b</code>中，由于<code>页b</code>现在有足够的空间容纳一条记录，所以直接将该记录插入到<code>页b</code>中就好了，就像这样：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/16948930120794a0?w=711&amp;h=559&amp;f=png&amp;s=44305" alt="image_1d4fcbg9e1m1b1qtj1emgphorrl2g.png-43.3kB"></p></li> <li><p>情况二：该数据页剩余的空闲空间不足，那么事情就悲剧了，我们前边说过，遇到这种情况要进行所谓的<code>页分裂</code>操作，也就是新建一个叶子节点，然后把原先数据页中的一部分记录复制到这个新的数据页中，然后再把记录插入进去，把这个叶子节点插入到叶子节点链表中，最后还要在内节点中添加一条<code>目录项记录</code>指向这个新创建的页面。很显然，这个过程要对多个页面进行修改，也就意味着会产生多条<code>redo</code>日志，我们把这种情况称之为<code>悲观插入</code>。假如某个索引对应的<code>B+</code>树长这样：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/1694893011fc216e?w=731&amp;h=551&amp;f=png&amp;s=45566" alt="image_1d4fcomne1lpsp691hg2o416hh2t.png-44.5kB"></p> <p>现在我们要插入一条键值为<code>10</code>的记录，很显然需要被插入到<code>页b</code>中，但是从图中也可以看出来，此时<code>页b</code>已经塞满了记录，没有更多的空闲空间来容纳这条新记录了，所以我们需要进行页面的分裂操作，就像这样：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/16948930147d598e?w=951&amp;h=570&amp;f=png&amp;s=99256" alt="image_1d4fkn8gv1n7enuq23kt1n1uvk3n.png-96.9kB"></p> <p>如果作为内节点的<code>页a</code>的剩余空闲空间也不足以容纳增加一条<code>目录项记录</code>，那需要继续做内节点<code>页a</code>的分裂操作，也就意味着会修改更多的页面，从而产生更多的<code>redo</code>日志。另外，对于<code>悲观插入</code>来说，由于需要新申请数据页，还需要改动一些系统页面，比方说要修改各种段、区的统计信息信息，各种链表的统计信息（比如什么<code>FREE</code>链表、<code>FSP_FREE_FRAG</code>链表吧啦吧啦我们在唠叨表空间那一章中介绍过的各种东东）等等等等，反正总共需要记录的<code>redo</code>日志有二、三十条。</p></li></ul> <div class="language-! extra-class"><pre class="language-text"><code>小贴士：

其实不光是悲观插入一条记录会生成许多条redo日志，设计InnoDB的大叔为了其他的一些功能，在乐观插入时也可能产生多条redo日志（具体是为了什么功能我们就不多说了，要不篇幅就受不了了～）。
</code></pre></div><p>设计<code>InnoDB</code>的大叔们认为向某个索引对应的<code>B+</code>树中插入一条记录的这个过程必须是原子的，不能说插了一半之后就停止了。比方说在悲观插入过程中，新的页面已经分配好了，数据也复制过去了，新的记录也插入到页面中了，可是没有向内节点中插入一条<code>目录项记录</code>，这个插入过程就是不完整的，这样会形成一棵不正确的<code>B+</code>树。我们知道<code>redo</code>日志是为了在系统奔溃重启时恢复崩溃前的状态，如果在悲观插入的过程中只记录了一部分<code>redo</code>日志，那么在系统奔溃重启时会将索引对应的<code>B+</code>树恢复成一种不正确的状态，这是设计<code>InnoDB</code>的大叔们所不能忍受的。所以他们规定在执行这些需要保证原子性的操作时必须以<code>组</code>的形式来记录的<code>redo</code>日志，在进行系统奔溃重启恢复时，针对某个组中的<code>redo</code>日志，要么把全部的日志都恢复掉，要么一条也不恢复。怎么做到的呢？这得分情况讨论：</p> <ul><li><p>有的需要保证原子性的操作会生成多条<code>redo</code>日志，比如向某个索引对应的<code>B+</code>树中进行一次悲观插入就需要生成许多条<code>redo</code>日志。</p> <p>如何把这些<code>redo</code>日志划分到一个组里边儿呢？设计<code>InnoDB</code>的大叔做了一个很简单的小把戏，就是在该组中的最后一条<code>redo</code>日志后边加上一条特殊类型的<code>redo</code>日志，该类型名称为<code>MLOG_MULTI_REC_END</code>，<code>type</code>字段对应的十进制数字为<code>31</code>，该类型的<code>redo</code>日志结构很简单，只有一个<code>type</code>字段：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/16948930162d677f?w=539&amp;h=199&amp;f=png&amp;s=15317" alt="image_1d4fna6k51fok1mpd1tikkmihg144.png-15kB"></p> <p>所以某个需要保证原子性的操作产生的一系列<code>redo</code>日志必须要以一个类型为<code>MLOG_MULTI_REC_END</code>结尾，就像这样：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/16948930164d64a0?w=961&amp;h=300&amp;f=png&amp;s=42384" alt="image_1d4fol2v71fjalphluu1kuf1d8t4h.png-41.4kB"></p> <p>这样在系统奔溃重启进行恢复时，只有当解析到类型为<code>MLOG_MULTI_REC_END</code>的<code>redo</code>日志，才认为解析到了一组完整的<code>redo</code>日志，才会进行恢复。否则的话直接放弃前边解析到的<code>redo</code>日志。</p></li> <li><p>有的需要保证原子性的操作只生成一条<code>redo</code>日志，比如更新<code>Max Row ID</code>属性的操作就只会生成一条<code>redo</code>日志。</p> <p>其实在一条日志后边跟一个类型为<code>MLOG_MULTI_REC_END</code>的<code>redo</code>日志也是可以的，不过设计<code>InnoDB</code>的大叔比较勤俭节约，他们不想浪费一个比特位。别忘了虽然<code>redo</code>日志的类型比较多，但撑死了也就是几十种，是小于<code>127</code>这个数字的，也就是说我们用7个比特位就足以包括所有的<code>redo</code>日志类型，而<code>type</code>字段其实是占用1个字节的，也就是说我们可以省出来一个比特位用来表示该需要保证原子性的操作只产生单一的一条<code>redo</code>日志，示意图如下：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/169489301685dcb4?w=869&amp;h=282&amp;f=png&amp;s=28021" alt="image_1d4fqlji7md35pdmvvhvibqb4u.png-27.4kB"></p> <p>如果<code>type</code>字段的第一个比特位为<code>1</code>，代表该需要保证原子性的操作只产生了单一的一条<code>redo</code>日志，否则表示该需要保证原子性的操作产生了一系列的<code>redo</code>日志。</p></li></ul> <h3 id="mini-transaction的概念"><a href="#mini-transaction的概念" class="header-anchor">#</a> Mini-Transaction的概念</h3> <p>设计<code>MySQL</code>的大叔把对底层页面中的一次原子访问的过程称之为一个<code>Mini-Transaction</code>，简称<code>mtr</code>，比如上边所说的修改一次<code>Max Row ID</code>的值算是一个<code>Mini-Transaction</code>，向某个索引对应的<code>B+</code>树中插入一条记录的过程也算是一个<code>Mini-Transaction</code>。通过上边的叙述我们也知道，一个所谓的<code>mtr</code>可以包含一组<code>redo</code>日志，在进行奔溃恢复时这一组<code>redo</code>日志作为一个不可分割的整体。</p> <p>一个事务可以包含若干条语句，每一条语句其实是由若干个<code>mtr</code>组成，每一个<code>mtr</code>又可以包含若干条<code>redo</code>日志，画个图表示它们的关系就是这样：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/169489303b9e5c9f?w=619&amp;h=559&amp;f=png&amp;s=28248" alt="image_1d4hgjr7t4es1v2mf2b1bt51rf95b.png-27.6kB"></p> <h2 id="redo日志的写入过程"><a href="#redo日志的写入过程" class="header-anchor">#</a> redo日志的写入过程</h2> <h3 id="redo-log-block"><a href="#redo-log-block" class="header-anchor">#</a> redo log block</h3> <p>设计<code>InnoDB</code>的大叔为了更好的进行系统奔溃恢复，他们把通过<code>mtr</code>生成的<code>redo</code>日志都放在了大小为<code>512字节</code>的<code>页</code>中。为了和我们前边提到的表空间中的页做区别，我们这里把用来存储<code>redo</code>日志的页称为<code>block</code>（你心里清楚页和block的意思其实差不多就行了）。一个<code>redo log block</code>的示意图如下：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/169489303bff8e20?w=785&amp;h=416&amp;f=png&amp;s=58592" alt="image_1d4hor6e7nq1mkm1sa41he71rif75.png-57.2kB"></p> <p>真正的<code>redo</code>日志都是存储到占用<code>496</code>字节大小的<code>log block body</code>中，图中的<code>log block header</code>和<code>log block trailer</code>存储的是一些管理信息。我们来看看这些所谓的<code>管理信息</code>都是啥：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/169489303c1fb389?w=998&amp;h=521&amp;f=png&amp;s=116667" alt="image_1d4hp4u8g13e317mkngoag21clv7i.png-113.9kB"></p> <p>其中<code>log block header</code>的几个属性的意思分别如下：</p> <ul><li><p><code>LOG_BLOCK_HDR_NO</code>：每一个block都有一个大于0的唯一标号，本属性就表示该标号值。</p></li> <li><p><code>LOG_BLOCK_HDR_DATA_LEN</code>：表示block中已经使用了多少字节，初始值为<code>12</code>（因为<code>log block body</code>从第12个字节处开始）。随着往block中写入的redo日志越来也多，本属性值也跟着增长。如果<code>log block body</code>已经被全部写满，那么本属性的值被设置为<code>512</code>。</p></li> <li><p><code>LOG_BLOCK_FIRST_REC_GROUP</code>：一条<code>redo</code>日志也可以称之为一条<code>redo</code>日志记录（<code>redo log record</code>），一个<code>mtr</code>会生产多条<code>redo</code>日志记录，这些<code>redo</code>日志记录被称之为一个<code>redo</code>日志记录组（<code>redo log record group</code>）。<code>LOG_BLOCK_FIRST_REC_GROUP</code>就代表该block中第一个<code>mtr</code>生成的<code>redo</code>日志记录组的偏移量（其实也就是这个block里第一个<code>mtr</code>生成的第一条<code>redo</code>日志的偏移量）。</p></li> <li><p><code>LOG_BLOCK_CHECKPOINT_NO</code>：表示所谓的<code>checkpoint</code>的序号，<code>checkpoint</code>是我们后续内容的重点，现在先不用清楚它的意思，稍安勿躁。</p></li></ul> <p><code>log block trailer</code>中属性的意思如下：</p> <ul><li><code>LOG_BLOCK_CHECKSUM</code>：表示block的校验值，用于正确性校验，我们暂时不关心它。</li></ul> <h3 id="redo日志缓冲区"><a href="#redo日志缓冲区" class="header-anchor">#</a> redo日志缓冲区</h3> <p>我们前边说过，设计<code>InnoDB</code>的大叔为了解决磁盘速度过慢的问题而引入了<code>Buffer Pool</code>。同理，写入<code>redo</code>日志时也不能直接直接写到磁盘上，实际上在服务器启动时就向操作系统申请了一大片称之为<code>redo log buffer</code>的连续内存空间，翻译成中文就是<code>redo日志缓冲区</code>，我们也可以简称为<code>log buffer</code>。这片内存空间被划分成若干个连续的<code>redo log block</code>，就像这样：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/169489303ceeb982?w=995&amp;h=459&amp;f=png&amp;s=78303" alt="image_1d4i4orkr17vl1m5l3hl1l341pad1j.png-76.5kB"></p> <p>我们可以通过启动参数<code>innodb_log_buffer_size</code>来指定<code>log buffer</code>的大小，在<code>MySQL 5.7.21</code>这个版本中，该启动参数的默认值为<code>16MB</code>。</p> <h3 id="redo日志写入log-buffer"><a href="#redo日志写入log-buffer" class="header-anchor">#</a> redo日志写入log buffer</h3> <p>向<code>log buffer</code>中写入<code>redo</code>日志的过程是顺序的，也就是先往前边的block中写，当该block的空闲空间用完之后再往下一个block中写。当我们想往<code>log buffer</code>中写入<code>redo</code>日志时，第一个遇到的问题就是应该写在哪个<code>block</code>的哪个偏移量处，所以设计<code>InnoDB</code>的大叔特意提供了一个称之为<code>buf_free</code>的全局变量，该变量指明后续写入的<code>redo</code>日志应该写入到<code>log buffer</code>中的哪个位置，如图所示：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/1694893043dc7344?w=842&amp;h=542&amp;f=png&amp;s=100778" alt="image_1d4jsb3pac9t1pl76drruf1b0574.png-98.4kB"></p> <p>我们前边说过一个<code>mtr</code>执行过程中可能产生若干条<code>redo</code>日志，这些<code>redo</code>日志是一个不可分割的组，所以其实并不是每生成一条<code>redo</code>日志，就将其插入到<code>log buffer</code>中，而是每个<code>mtr</code>运行过程中产生的日志先暂时存到一个地方，当该<code>mtr</code>结束的时候，将过程中产生的一组<code>redo</code>日志再全部复制到<code>log buffer</code>中。我们现在假设有两个名为<code>T1</code>、<code>T2</code>的事务，每个事务都包含2个<code>mtr</code>，我们给这几个<code>mtr</code>命名一下：</p> <ul><li><p>事务<code>T1</code>的两个<code>mtr</code>分别称为<code>mtr_T1_1</code>和<code>mtr_T1_2</code>。</p></li> <li><p>事务<code>T2</code>的两个<code>mtr</code>分别称为<code>mtr_T2_1</code>和<code>mtr_T2_2</code>。</p></li></ul> <p>每个<code>mtr</code>都会产生一组<code>redo</code>日志，用示意图来描述一下这些<code>mtr</code>产生的日志情况：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/2/25/1692548dcc3fe243?w=956&amp;h=507&amp;f=png&amp;s=97414" alt="image_1d4ie92r31t57c94e661n861skv2t.png-95.1kB"></p> <p>不同的事务可能是并发执行的，所以<code>T1</code>、<code>T2</code>之间的<code>mtr</code>可能是交替执行的。每当一个<code>mtr</code>执行完成时，伴随该<code>mtr</code>生成的一组<code>redo</code>日志就需要被复制到<code>log buffer</code>中，也就是说不同事务的<code>mtr</code>可能是交替写入<code>log buffer</code>的，我们画个示意图（为了美观，我们把一个<code>mtr</code>中产生的所有的<code>redo</code>日志当作一个整体来画）：</p> <p><img src="https://user-gold-cdn.xitu.io/2019/3/4/169489304969c9d7?w=823&amp;h=419&amp;f=png&amp;s=105070" alt="image_1d4jsd7861q6dn9n17gs1cdd1kek7h.png-102.6kB"></p> <p>从示意图中我们可以看出来，不同的<code>mtr</code>产生的一组<code>redo</code>日志占用的存储空间可能不一样，有的<code>mtr</code>产生的<code>redo</code>日志量很少，比如<code>mtr_t1_1</code>、<code>mtr_t2_1</code>就被放到同一个block中存储，有的<code>mtr</code>产生的<code>redo</code>日志量非常大，比如<code>mtr_t1_2</code>产生的<code>redo</code>日志甚至占用了3个block来存储。</p> <div class="language-! extra-class"><pre class="language-text"><code>小贴士：

对照着上图，自己分析一下每个block的LOG_BLOCK_HDR_DATA_LEN、LOG_BLOCK_FIRST_REC_GROUP属性值都是什么哈～
</code></pre></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">上次更新:</span> <span class="time">9/30/2020, 6:12:29 AM</span></div></footer> <!----> </main></div><div class="global-ui"></div></div>
    <script src="/assets/js/app.cb35c8f6.js" defer></script><script src="/assets/js/2.063846a6.js" defer></script><script src="/assets/js/4.1ffb4609.js" defer></script><script src="/assets/js/611.bb8058c9.js" defer></script>
  </body>
</html>
